WDK Mini Filter Example
change.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation. All Rights Reserved
4 
5 Module Name:
6 
7  change.c
8 
9 Abstract:
10 
11  This is the main module of the change miniFilter driver.
12  This transaction-aware filter monitors file changes in real time.
13  Cg prefix denotes "Change" module.
14 
15  This module tracks if the files are dirty. In order to do this,
16  we have to intercept the "write" I/O requests. In particular,
17  the operations are collected in CgOperationsNeedDirty(...) function.
18  If you care about more than the contents of the file, you may need to
19  modify this function accordingly.
20 
21  This sample demonstrates how to track whether a file has been modified.
22 
23  In addition, this filter handles the case that the transaction
24  commits or rollbacks. The overview of a transaction-aware
25  minifilter is stated as follows
26 
27  1. At post create, if a transacted file is open with attribute
28  FILE_WRITE_DATA or FILE_APPEND_DATA, then we would enlist its
29  file context into the transaction context.
30 
31  2. At pre-operation callback, if the operation needs to be dirty,
32  such as IRP_MJ_WRITE and the file is part of a transaction,
33  we update its TxDirty instead of Dirty.
34 
35  3. At KTM notification callback, if the transaction committed,
36  then propagate the dirty information from TxDirty to Dirty;
37  if rollbacked, do not propagate.
38 
39  4. Properly remove the list at TransactionContextCleanup.
40 
41 Environment:
42 
43  Kernel mode
44 
45 --*/
46 
47 #include "change.h"
48 
49 /*************************************************************************
50  Local Function Prototypes
51 *************************************************************************/
52 
53 DRIVER_INITIALIZE DriverEntry;
54 NTSTATUS
56  _In_ PDRIVER_OBJECT DriverObject,
57  _In_ PUNICODE_STRING RegistryPath
58  );
59 
60 NTSTATUS
62  _In_ PCFLT_RELATED_OBJECTS FltObjects,
63  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
64  _In_ DEVICE_TYPE VolumeDeviceType,
65  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
66  );
67 
68 VOID
70  _In_ PCFLT_RELATED_OBJECTS FltObjects,
71  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
72  );
73 
74 VOID
76  _In_ PCFLT_RELATED_OBJECTS FltObjects,
77  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
78  );
79 
80 NTSTATUS
81 CgUnload (
82  _In_ FLT_FILTER_UNLOAD_FLAGS Flags
83  );
84 
85 NTSTATUS
87  _In_ PCFLT_RELATED_OBJECTS FltObjects,
88  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
89  );
90 
91 FLT_PREOP_CALLBACK_STATUS
93  _Inout_ PFLT_CALLBACK_DATA Data,
94  _In_ PCFLT_RELATED_OBJECTS FltObjects,
95  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
96  );
97 
98 FLT_PREOP_CALLBACK_STATUS
100  _Inout_ PFLT_CALLBACK_DATA Data,
101  _In_ PCFLT_RELATED_OBJECTS FltObjects,
102  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
103  );
104 
105 FLT_POSTOP_CALLBACK_STATUS
106 CgPostCreate (
107  _Inout_ PFLT_CALLBACK_DATA Data,
108  _In_ PCFLT_RELATED_OBJECTS FltObjects,
109  _In_opt_ PVOID CompletionContext,
110  _In_ FLT_POST_OPERATION_FLAGS Flags
111  );
112 
113 FLT_PREOP_CALLBACK_STATUS
114 CgPreClose (
115  _Inout_ PFLT_CALLBACK_DATA Data,
116  _In_ PCFLT_RELATED_OBJECTS FltObjects,
117  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
118  );
119 
120 FLT_PREOP_CALLBACK_STATUS
122  _Inout_ PFLT_CALLBACK_DATA Data,
123  _In_ PCFLT_RELATED_OBJECTS FltObjects,
124  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
125  );
126 
127 NTSTATUS
129  _In_ PCFLT_RELATED_OBJECTS FltObjects,
130  _In_ PFLT_CONTEXT TransactionContext,
131  _In_ ULONG TransactionNotification
132  );
133 
134 //
135 // Local routines
136 //
137 
138 BOOLEAN
140  _In_ PFLT_CALLBACK_DATA Data
141  );
142 
143 NTSTATUS
145  _In_ PKTRANSACTION Transaction,
146  _Out_ PULONG TxOutcome
147  );
148 
149 NTSTATUS
151  _In_ PCFLT_RELATED_OBJECTS FltObjects,
152  _Inout_ PCG_FILE_CONTEXT FileContext
153  );
154 
155 NTSTATUS
157  _Inout_ PCG_TRANSACTION_CONTEXT TransactionContext,
158  _In_ ULONG TransactionOutcome
159  );
160 
161 
162 //
163 // Assign text sections for each routine.
164 //
165 
166 #ifdef ALLOC_PRAGMA
167 #pragma alloc_text(INIT, DriverEntry)
168 #pragma alloc_text(PAGE, CgUnload)
169 #pragma alloc_text(PAGE, CgInstanceQueryTeardown)
170 #pragma alloc_text(PAGE, CgInstanceSetup)
171 #pragma alloc_text(PAGE, CgInstanceTeardownStart)
172 #pragma alloc_text(PAGE, CgInstanceTeardownComplete)
173 #pragma alloc_text(PAGE, CgInstanceTeardownComplete)
174 #pragma alloc_text(PAGE, CgPreCreate)
175 #pragma alloc_text(PAGE, CgPreFsControl)
176 #pragma alloc_text(PAGE, CgPostCreate)
177 #pragma alloc_text(PAGE, CgPreClose)
178 #pragma alloc_text(PAGE, CgKtmNotificationCallback)
179 #pragma alloc_text(PAGE, CgProcessPreviousTransaction)
180 #pragma alloc_text(PAGE, CgProcessTransactionOutcome)
181 #pragma alloc_text(PAGE, CgQueryTransactionOutcome)
182 #endif
183 
184 
185 //
186 // operation registration
187 //
188 
189 CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
190  { IRP_MJ_CREATE,
191  0,
192  CgPreCreate,
193  CgPostCreate },
194 
195  { IRP_MJ_CLOSE,
196  0,
197  CgPreClose,
198  NULL },
199 
200  { IRP_MJ_WRITE,
201  0,
203  NULL },
204 
206  0,
208  NULL },
209 
211  0,
213  NULL },
214 
215  { IRP_MJ_OPERATION_END }
216 };
217 
218 //
219 // Context registraction construct defined in context.c
220 //
221 
222 extern const FLT_CONTEXT_REGISTRATION ContextRegistration[];
223 
224 //
225 // This defines what we want to filter with FltMgr
226 //
227 
228 CONST FLT_REGISTRATION FilterRegistration = {
229 
230  sizeof( FLT_REGISTRATION ), // Size
231  FLT_REGISTRATION_VERSION, // Version
232  0, // Flags
233 
234  ContextRegistration, // Context
235  Callbacks, // Operation callbacks
236 
237  CgUnload, // MiniFilterUnload
238 
239  CgInstanceSetup, // InstanceSetup
240  CgInstanceQueryTeardown, // InstanceQueryTeardown
241  CgInstanceTeardownStart, // InstanceTeardownStart
242  CgInstanceTeardownComplete, // InstanceTeardownComplete
243 
244  NULL, // GenerateFileName
245  NULL, // GenerateDestinationFileName
246  NULL, // NormalizeNameComponent
247  CgKtmNotificationCallback // KTM notification callback
248 
249 };
250 
251 
252 
253 NTSTATUS
255  _In_ PCFLT_RELATED_OBJECTS FltObjects,
256  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
257  _In_ DEVICE_TYPE VolumeDeviceType,
258  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
259  )
260 /*++
261 
262 Routine Description:
263 
264  This routine is called whenever a new instance is created on a volume. This
265  gives us a chance to decide if we need to attach to this volume or not.
266 
267  If this routine is not defined in the registration structure, automatic
268  instances are always created.
269 
270 Arguments:
271 
272  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
273  opaque handles to this filter, instance and its associated volume.
274 
275  Flags - Flags describing the reason for this attach request.
276 
277 Return Value:
278 
279  STATUS_SUCCESS - attach
280  STATUS_FLT_DO_NOT_ATTACH - do not attach
281 
282 --*/
283 {
284  UNREFERENCED_PARAMETER( FltObjects );
285  UNREFERENCED_PARAMETER( Flags );
286  UNREFERENCED_PARAMETER( VolumeDeviceType );
287  UNREFERENCED_PARAMETER( VolumeFilesystemType );
288 
289  PAGED_CODE();
290 
292  ("[CG] CgInstanceSetup: Entered\n") );
293 
294  return STATUS_SUCCESS;
295 }
296 
297 
298 NTSTATUS
300  _In_ PCFLT_RELATED_OBJECTS FltObjects,
301  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
302  )
303 /*++
304 
305 Routine Description:
306 
307  This is called when an instance is being manually deleted by a
308  call to FltDetachVolume or FilterDetach thereby giving us a
309  chance to fail that detach request.
310 
311  If this routine is not defined in the registration structure, explicit
312  detach requests via FltDetachVolume or FilterDetach will always be
313  failed.
314 
315 Arguments:
316 
317  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
318  opaque handles to this filter, instance and its associated volume.
319 
320  Flags - Indicating where this detach request came from.
321 
322 Return Value:
323 
324  Returns the status of this operation.
325 
326 --*/
327 {
328  UNREFERENCED_PARAMETER( FltObjects );
329  UNREFERENCED_PARAMETER( Flags );
330 
331  PAGED_CODE();
332 
334  ("[CG] CgInstanceQueryTeardown: Entered\n") );
335 
336  return STATUS_SUCCESS;
337 }
338 
339 
340 VOID
342  _In_ PCFLT_RELATED_OBJECTS FltObjects,
343  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
344  )
345 /*++
346 
347 Routine Description:
348 
349  This routine is called at the start of instance teardown.
350 
351 Arguments:
352 
353  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
354  opaque handles to this filter, instance and its associated volume.
355 
356  Flags - Reason why this instance is been deleted.
357 
358 Return Value:
359 
360  None.
361 
362 --*/
363 {
364  UNREFERENCED_PARAMETER( FltObjects );
365  UNREFERENCED_PARAMETER( Flags );
366 
367  PAGED_CODE();
368 
370  ("[CG] CgInstanceTeardownStart: Entered\n") );
371 }
372 
373 
374 VOID
376  _In_ PCFLT_RELATED_OBJECTS FltObjects,
377  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
378  )
379 /*++
380 
381 Routine Description:
382 
383  This routine is called at the end of instance teardown.
384 
385 Arguments:
386 
387  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
388  opaque handles to this filter, instance and its associated volume.
389 
390  Flags - Reason why this instance is been deleted.
391 
392 Return Value:
393 
394  None.
395 
396 --*/
397 {
398  UNREFERENCED_PARAMETER( FltObjects );
399  UNREFERENCED_PARAMETER( Flags );
400 
401  PAGED_CODE();
402 
404  ("[CG] CgInstanceTeardownComplete: Entered\n") );
405 }
406 
407 
408 /*************************************************************************
409  MiniFilter initialization and unload routines.
410 *************************************************************************/
411 
412 NTSTATUS
414  _In_ PDRIVER_OBJECT DriverObject,
415  _In_ PUNICODE_STRING RegistryPath
416  )
417 /*++
418 
419 Routine Description:
420 
421  This is the initialization routine for this miniFilter driver. This
422  registers with FltMgr and initializes all global data structures.
423 
424 Arguments:
425 
426  DriverObject - Pointer to driver object created by the system to
427  represent this driver.
428 
429  RegistryPath - Unicode string identifying where the parameters for this
430  driver are located in the registry.
431 
432 Return Value:
433 
434  Returns the final status of this operation.
435 
436 --*/
437 {
438  NTSTATUS status;
439 
440  UNREFERENCED_PARAMETER( RegistryPath );
441 
443  ("[CG] DriverEntry: Entered\n") );
444 
445  //
446  // Register with FltMgr to tell it our callback routines
447  //
448 
449  status = FltRegisterFilter( DriverObject,
451  &gFilterInstance );
452 
453  if (NT_SUCCESS( status )) {
454 
455  //
456  // Start filtering i/o
457  //
458 
459  status = FltStartFiltering( gFilterInstance );
460 
461  if (!NT_SUCCESS( status )) {
462 
463  FltUnregisterFilter( gFilterInstance );
464  }
465  }
466 
467  return status;
468 }
469 
470 NTSTATUS
472  _In_ FLT_FILTER_UNLOAD_FLAGS Flags
473  )
474 /*++
475 
476 Routine Description:
477 
478  This is the unload routine for this miniFilter driver. This is called
479  when the minifilter is about to be unloaded. We can fail this unload
480  request if this is not a mandatory unloaded indicated by the Flags
481  parameter.
482 
483 Arguments:
484 
485  Flags - Indicating if this is a mandatory unload.
486 
487 Return Value:
488 
489  Returns the final status of this operation.
490 
491 --*/
492 {
493  UNREFERENCED_PARAMETER( Flags );
494 
495  PAGED_CODE();
496 
498  ("[CG] CgUnload: Entered\n") );
499 
500 
501  FltUnregisterFilter( gFilterInstance );
503 
504  return STATUS_SUCCESS;
505 }
506 
507 
508 /*************************************************************************
509  Local utility routines.
510 *************************************************************************/
511 
512 BOOLEAN
514  _In_ PFLT_CALLBACK_DATA Data
515  )
516 /*++
517 
518 Routine Description:
519 
520  This identifies those operations we need to set the file to be dirty.
521  This is non-pageable because it could be called on the paging path
522 
523 Arguments:
524 
525  Data - Pointer to the filter callbackData that is passed to us.
526 
527 Return Value:
528 
529  TRUE - If we want the file associated with the request to be dirty.
530  FALSE - If we don't
531 
532 --*/
533 {
534  PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb;
535 
536  //
537  // In this example, we only care about the "contents" of the file.
538  // The dirty concept depends on what you care about. If you care
539  // about the file metadata, for example, then you should have to add
540  // the operations that modify the file metadata as well.
541  //
542 
543  switch(iopb->MajorFunction) {
544 
545  case IRP_MJ_WRITE:
546  return TRUE;
547 
549  switch ( iopb->Parameters.FileSystemControl.Common.FsControlCode ) {
550  case FSCTL_OFFLOAD_WRITE:
551  case FSCTL_WRITE_RAW_ENCRYPTED:
552  case FSCTL_SET_ZERO_DATA:
553  return TRUE;
554  default: break;
555  }
556  break;
557 
559  switch ( iopb->Parameters.SetFileInformation.FileInformationClass ) {
560  case FileEndOfFileInformation:
561  case FileValidDataLengthInformation:
562  return TRUE;
563  default: break;
564  }
565  break;
566  default:
567  break;
568  }
569  return FALSE;
570 }
571 
572 NTSTATUS
574  _In_ PKTRANSACTION Transaction,
575  _Out_ PULONG TxOutcome
576  )
577 /*++
578 
579 Routine Description:
580 
581  This is a helper function that qeury the KTM that how trasnaction was ended.
582 
583 Arguments:
584 
585  Transaction - Pointer to transaction object.
586 
587  TxOutcome - Output. Specifies the type of transaction outcome.
588 
589 Return Value:
590 
591  The status of the operation
592 --*/
593 {
594  HANDLE transactionHandle;
595  NTSTATUS status;
596  TRANSACTION_BASIC_INFORMATION txBasicInfo = {0};
597 
598  PAGED_CODE();
599 
600  status = ObOpenObjectByPointer( Transaction,
601  OBJ_KERNEL_HANDLE,
602  NULL,
603  GENERIC_READ,
604  *TmTransactionObjectType,
605  KernelMode,
606  &transactionHandle );
607 
608  if (!NT_SUCCESS(status)) {
609 
611  ("[CG] CgQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") );
612  return status;
613  }
614 
615  status = ZwQueryInformationTransaction( transactionHandle,
616  TransactionBasicInformation,
617  &txBasicInfo,
618  sizeof(TRANSACTION_BASIC_INFORMATION),
619  NULL );
620  if (!NT_SUCCESS(status)) {
621 
623  ("[CG] CgQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") );
624  goto Cleanup;
625  }
626 
627  *TxOutcome = txBasicInfo.Outcome;
628 
629 Cleanup:
630 
631  ZwClose(transactionHandle);
632 
633  return status;
634 }
635 
636 FORCEINLINE
637 VOID
639  _Inout_ PCG_FILE_CONTEXT FileContext,
640  _In_ ULONG TransactionOutcome
641  )
642 {
643 
644  if (TransactionOutcome == TransactionOutcomeCommitted) {
645 
646  //
647  // The 'or' operator here handles the case below:
648  //
649  // It is possible that the user only read the file even if it opens the file transacted file read and write.
650  // So, fileContext->TxDirty is possible to be FALSE.
651  //
652  // Since KTM callback is asynchrounous, notifications are not necessarily received in order.
653  // It is possible that dirty information will be wiped out if we use
654  //
655  // fileContext->Dirty = fileContext->TxDirty;
656  //
657 
658  FileContext->Dirty |= FileContext->TxDirty;
659  }
660 
661  //
662  // Clear TxDirty regardless of transaction outcome.
663  //
664 
665  FileContext->TxDirty = FALSE;
666 }
667 
668 NTSTATUS
670  _In_ PCFLT_RELATED_OBJECTS FltObjects,
671  _Inout_ PCG_FILE_CONTEXT FileContext
672  )
673 /*++
674 
675 Routine Description:
676 
677  This routine is transaction related implementation, and is expected to be
678  invoked at post-create. Note that this function will enlist the newly
679  allocated transaction context via FltEnlistInTransaction if it needs to.
680 
681 Arguments:
682 
683  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
684  opaque handles to this filter, instance, its associated volume and
685  file object.
686 
687  FileContext - The file context.
688 
689 Return Value:
690 
691  The return value is the status of the operation.
692 
693 --*/
694 {
695  ULONG txOutcome = TransactionOutcomeUndetermined;
696  NTSTATUS status = STATUS_SUCCESS;
697  PCG_TRANSACTION_CONTEXT oldTxCtx = NULL;
698  PCG_TRANSACTION_CONTEXT transactionContext = NULL;
699 
700  PAGED_CODE();
701 
702  if (FltObjects->Transaction != NULL) {
703 
704  //
705  // Get transaction context
706  //
707 
708  status = CgFindOrCreateTransactionContext( FltObjects,
709  &transactionContext );
710 
711  if (!NT_SUCCESS( status )) {
712 
714  ("[CG] CgProcessPreviousTransaction: CgFindOrCreateTransactionContext FAILED\n") );
715  transactionContext = NULL;
716  goto Cleanup;
717  }
718 
719  //
720  // Enlist it if haven't.
721  //
722 
723  if (!transactionContext->Enlisted) {
724 
725  status = FltEnlistInTransaction( FltObjects->Instance,
726  FltObjects->Transaction,
727  transactionContext,
728  TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK );
729 
730  if (!NT_SUCCESS( status ) && (status != STATUS_FLT_ALREADY_ENLISTED) ) {
731 
733  ("[CG] CgProcessPreviousTransaction: FltEnlistInTransaction FAILED!!!!\n") );
734  goto Cleanup;
735  }
736 
737  status = STATUS_SUCCESS;
738  transactionContext->Enlisted = TRUE;
739  }
740  }
741 
742  //
743  // Here we have five cases:
744  //
745  // 1)
746  // oldTxCtx : NULL
747  // transCtx : B
748  // 2)
749  // oldTxCtx : A
750  // transCtx : NULL
751  // 3)
752  // oldTxCtx : A
753  // transCtx : B
754  // 4)
755  // oldTxCtx : A
756  // transCtx : A
757  // 5)
758  // oldTxCtx : NULL
759  // transCtx : NULL
760  //
761 
762  //
763  // Synchronize the replacement of FileContext->TxContext with KTM callback.
764  //
765 
766  oldTxCtx = InterlockedExchangePointer( &FileContext->TxContext, transactionContext );
767 
768  if (oldTxCtx != transactionContext) { // case 1,2,3
769 
770  if ( oldTxCtx == NULL ) { // case 1
771 
772  //
773  // Since we exchanged the pointer, we need to increment the referece count
774  //
775 
776  FltReferenceContext ( transactionContext );
777 
778  //
779  // Before insertion into the FcList in transaction context, we increment file context's ref count
780  //
781 
782  ExAcquireFastMutex( transactionContext->Mutex );
783 
784  if (!transactionContext->ListDrained) {
785 
786  FltReferenceContext ( FileContext ); // Q
787  InsertTailList( &transactionContext->ScListHead,
788  &FileContext->ListInTransaction );
789  }
790 
791  ExReleaseFastMutex( transactionContext->Mutex );
792 
793  goto Cleanup;
794  }
795 
796  // case 2,3
797 
798  //
799  // There can only be one transacted writer for the file so the previous
800  // transaction must have finished. Whether or not the TxDirty state is propagated
801  // depends on its outcome so query that now.
802  //
803 
804  status = CgQueryTransactionOutcome( oldTxCtx->Transaction, &txOutcome );
805 
806  if (!NT_SUCCESS( status )) {
807 
808  //
809  // We have exchanged the transaction pointer already. If we can't get the outcome,
810  // we have to proceed anyway.
811  //
812 
814  ("[CG] CgProcessPreviousTransaction: CgQueryTransactionOutcome FAILED!!!!\n") );
815  }
816 
817  //
818  // Remove the file context from the original transaction context.
819  //
820 
821  ExAcquireFastMutex( oldTxCtx->Mutex );
822  RemoveEntryList ( &FileContext->ListInTransaction );
823  ExReleaseFastMutex( oldTxCtx->Mutex );
824 
825  CgPropagateDirty ( FileContext, txOutcome );
826 
827  if ( transactionContext ) { // case 3
828 
829  FltReferenceContext( transactionContext );
830 
831  ExAcquireFastMutex( transactionContext->Mutex );
832 
833  if (!transactionContext->ListDrained) {
834 
835  InsertTailList( &transactionContext->ScListHead,
836  &FileContext->ListInTransaction );
837 
838  } else {
839 
840  FltReleaseContext( FileContext );
841  }
842 
843  ExReleaseFastMutex( transactionContext->Mutex );
844 
845  } else { // case 2
846 
847  FltReleaseContext ( FileContext ); // Release reference count at Q
848  }
849 
850  // case 2,3
851 
852  FltReleaseContext( oldTxCtx ); // Release reference count in file context originally.
853 
854  }
855  //
856  // We don't care about case 4, 5.
857  //
858 
859 Cleanup:
860 
861  if (transactionContext) {
862 
863  FltReleaseContext( transactionContext ); // Release the ref count grabbed at CgFindOrCreateTransactionContext(...)
864  }
865 
866  return status;
867 }
868 
869 NTSTATUS
871  _Inout_ PCG_TRANSACTION_CONTEXT TransactionContext,
872  _In_ ULONG TransactionOutcome
873  )
874 /*++
875 
876 Routine Description:
877 
878  This is a helper function that process transaction commitment or rollback
879 
880 Arguments:
881 
882  TransactionContext - Pointer to the minifilter driver's transaction context
883  set at PostCreate.
884 
885  TransactionOutcome - Specifies the type of notifications. Should be either
886  TransactionOutcomeCommitted or TransactionOutcomeAborted
887 
888 Return Value:
889 
890  STATUS_SUCCESS - Returning this status value indicates that the minifilter
891  driver is finished with the transaction. This is a success code.
892 
893 --*/
894 {
895  PLIST_ENTRY scan;
896  PLIST_ENTRY next;
897  PCG_FILE_CONTEXT fileContext = NULL;
898  PCG_TRANSACTION_CONTEXT oldTxCtx = NULL;
899 
900  PAGED_CODE();
901 
902  //
903  // Tranversing the file context list, and
904  // sync the TxDirty -> Dirty.
905  //
906  // Either commit or rollback, we need to cleanup the list
907  // Tear down file context list inside transactionContext
908  //
909 
910  ExAcquireFastMutex( TransactionContext->Mutex );
911 
912  LIST_FOR_EACH_SAFE( scan, next, &TransactionContext->ScListHead ) {
913 
914  fileContext = CONTAINING_RECORD( scan, CG_FILE_CONTEXT, ListInTransaction );
915  oldTxCtx = InterlockedCompareExchangePointer( &fileContext->TxContext, NULL, TransactionContext );
916  if (oldTxCtx == TransactionContext) {
917 
918  //
919  // When oldTxCtx and TransactionContext are equal, it means that
920  // fileContext->TxContext has been successfully set to NULL.
921  //
922 
923  RemoveEntryList ( scan );
924  CgPropagateDirty( fileContext, TransactionOutcome );
925  FltReleaseContext( oldTxCtx );
926 
927  //
928  // This sample demonstrates how we propagate TxDirty to Dirty.
929  // If the file becomes dirty, we print out here.
930  //
931 
932  if (fileContext->Dirty) {
933 
935  ("[CG] CgProcessTransactionOutcome: Transacted file ID %I64x,%I64x is dirty\n",
936  fileContext->FileID.FileId64.UpperZeroes,
937  fileContext->FileID.FileId64.Value) );
938  }
939 
940  FltReleaseContext( fileContext );
941  }
942  }
943  TransactionContext->ListDrained = TRUE;
944  ExReleaseFastMutex( TransactionContext->Mutex );
945 
946 
947 
948  return STATUS_SUCCESS;
949 }
950 
951 /*************************************************************************
952  MiniFilter callback routines.
953 *************************************************************************/
954 
955 FLT_PREOP_CALLBACK_STATUS
957  _Inout_ PFLT_CALLBACK_DATA Data,
958  _In_ PCFLT_RELATED_OBJECTS FltObjects,
959  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
960  )
961 /*++
962 
963 Routine Description:
964 
965  This routine is the registered callback routine for filtering
966  the "write" operation, i.e. the operations that have potential
967  to make the file dirty.
968 
969  This is non-pageable because it could be called on the paging path
970 
971 Arguments:
972 
973  Data - Pointer to the filter callbackData that is passed to us.
974 
975  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
976  opaque handles to this filter, instance, its associated volume and
977  file object.
978 
979  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
980  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
981  the corresponding post-operation callback routine. Otherwise, it must be NULL.
982 
983 Return Value:
984 
985  The return value is the status of the operation.
986 
987 --*/
988 {
989  NTSTATUS status;
990  PCG_FILE_CONTEXT fileContext = NULL;
991 
992  UNREFERENCED_PARAMETER( CompletionContext );
993 
995  ("[CG] CgPreOperationCallback: Entered\n") );
996 
997  if (!CgOperationsNeedDirty(Data)) {
998 
999  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1000  }
1001 
1002  status = FltGetFileContext( FltObjects->Instance,
1003  FltObjects->FileObject,
1004  &fileContext );
1005 
1006  if (!NT_SUCCESS( status )) {
1007 
1009  ("[CG] CgPreOperationCallback: get file context failed. rq: %d\n",
1010  Data->Iopb->MajorFunction) );
1011 
1012  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1013  }
1014 
1015  //
1016  // If this operation is performed in a transacted writer view.
1017  //
1018 
1019  if (fileContext->TxContext != NULL) {
1020 
1021 #if DBG
1022  PCG_TRANSACTION_CONTEXT transactionContext = NULL;
1023 
1024  NTSTATUS statusTx = FltGetTransactionContext( FltObjects->Instance,
1025  FltObjects->Transaction,
1026  &transactionContext );
1027 
1028  FLT_ASSERTMSG( "Transaction context should not fail, because it is supposed to be created at post create.\n", NT_SUCCESS( statusTx ));
1029  FLT_ASSERTMSG( "The file's TxCtx should be identical with the target TxCtx.\n",
1030  fileContext->TxContext == transactionContext);
1031 
1032  if (NT_SUCCESS( statusTx )) {
1033  FltReleaseContext( transactionContext );
1034  }
1035 
1036 #endif // DBG
1037 
1038  //
1039  // Instead of updating Dirty, we update TxDirty here,
1040  // because this modification is occurring in the context of transaction
1041  // so if the transaction rolls back then the file will not be set as
1042  // Dirty, i.e. the dirty will not be propagated from TxDirty to Dity.
1043  // This is why we have TxDirty here.
1044  //
1045 
1046  fileContext->TxDirty = TRUE;
1047 
1048  } else {
1049 
1050  fileContext->Dirty = TRUE;
1051  }
1052 
1053  FltReleaseContext( fileContext );
1054 
1055  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1056 }
1057 
1058 FLT_PREOP_CALLBACK_STATUS
1060  _Inout_ PFLT_CALLBACK_DATA Data,
1061  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1062  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1063  )
1064 /*++
1065 
1066 Routine Description:
1067 
1068  Pre-file system control callback. This filter example does not support save point feature.
1069  So, we explicitly fail the request here.
1070 
1071 Arguments:
1072 
1073  Data - Pointer to the filter callbackData that is passed to us.
1074 
1075  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1076  opaque handles to this filter, instance, its associated volume and
1077  file object.
1078 
1079  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1080  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1081  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1082 
1083 Return Value:
1084 
1085  The return value is the status of the operation.
1086 
1087 --*/
1088 {
1089  PAGED_CODE();
1090 
1091  if (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_TXFS_SAVEPOINT_INFORMATION ) {
1092 
1093  //
1094  // We explicitly fail the request of save point here.
1095  //
1096 
1097  Data->IoStatus.Status = STATUS_NOT_SUPPORTED;
1098  return FLT_PREOP_COMPLETE;
1099  }
1100  return CgPreOperationCallback(Data, FltObjects, CompletionContext);
1101 }
1102 
1103 
1104 FLT_PREOP_CALLBACK_STATUS
1106  _Inout_ PFLT_CALLBACK_DATA Data,
1107  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1108  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1109  )
1110 /*++
1111 
1112 Routine Description:
1113 
1114  This routine is the pre-create completion routine.
1115  In this routine, file context and/or transaction context shall be
1116  created if not exits.
1117 
1118 Arguments:
1119 
1120  Data - Pointer to the filter callbackData that is passed to us.
1121 
1122  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1123  opaque handles to this filter, instance, its associated volume and
1124  file object.
1125 
1126  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1127  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1128  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1129 
1130 Return Value:
1131 
1132  FLT_PREOP_SYNCHRONIZE
1133 
1134 --*/
1135 {
1136 
1137  UNREFERENCED_PARAMETER( Data );
1138  UNREFERENCED_PARAMETER( FltObjects );
1139  UNREFERENCED_PARAMETER( CompletionContext );
1140 
1141  PAGED_CODE();
1142 
1144  ("[CG] CgPreOperationCallback: Entered\n") );
1145 
1146  //
1147  // Return FLT_PREOP_SYNCHRONIZE at PreCreate due to
1148  // some callback of PostCreate may be at DPC level.
1149  // eResource is required at level < DPC.
1150  //
1151 
1152  return FLT_PREOP_SYNCHRONIZE;
1153 
1154 }
1155 
1156 FLT_POSTOP_CALLBACK_STATUS
1158  _Inout_ PFLT_CALLBACK_DATA Data,
1159  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1160  _In_opt_ PVOID CompletionContext,
1161  _In_ FLT_POST_OPERATION_FLAGS Flags
1162  )
1163 /*++
1164 
1165 Routine Description:
1166 
1167  This routine is the post-create completion routine.
1168  In this routine, file context and/or transaction context shall be
1169  created if not exits.
1170 
1171 Arguments:
1172 
1173  Data - Pointer to the filter callbackData that is passed to us.
1174 
1175  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1176  opaque handles to this filter, instance, its associated volume and
1177  file object.
1178 
1179  CompletionContext - The completion context set in the pre-create routine.
1180 
1181  Flags - Denotes whether the completion is successful or is being drained.
1182 
1183 Return Value:
1184 
1185  The return value is the status of the operation.
1186 
1187 --*/
1188 {
1189  NTSTATUS status = Data->IoStatus.Status;
1190  PCG_FILE_CONTEXT fileContext = NULL;
1191 
1192  UNREFERENCED_PARAMETER( CompletionContext );
1193  UNREFERENCED_PARAMETER( Flags );
1194 
1195  PAGED_CODE();
1196 
1197  if (!NT_SUCCESS( status ) ||
1198  (status == STATUS_REPARSE)) {
1199 
1200  //
1201  // File creation may fail.
1202  //
1203 
1205  ("[CG] CgPostCreate: file creation failed\n") );
1206 
1207  return FLT_POSTOP_FINISHED_PROCESSING;
1208  }
1209 
1210  //
1211  // Find or create a file context
1212  //
1213 
1214  status = CgFindOrCreateFileContext( Data,
1215  &fileContext );
1216 
1217  if (!NT_SUCCESS( status )) {
1218 
1219  //
1220  // In this filter sample, if creation or retrieval of the contexts fails,
1221  // we let the creation go through because this example focuses on being
1222  // an non-intrusive filter. However, if tracking is critical for your
1223  // filter, then you should fail the create via FltCancelFileOpen(...).
1224  //
1225 
1227  ("[CG] CgPostCreate: find file context failed. \n") );
1228 
1229  return FLT_POSTOP_FINISHED_PROCESSING;
1230  }
1231 
1232  //
1233  // If successfully opened a file with the desired access matching
1234  // the "exclusive write" from a TxF point of view, we can know that
1235  // if previous transaction context exists, it must have been comitted
1236  // or rollbacked.
1237  //
1238 
1239  if (FlagOn( Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess,
1240  FILE_WRITE_DATA | FILE_APPEND_DATA |
1241  DELETE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
1242  WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY ) ) {
1243 
1244  status = CgProcessPreviousTransaction ( FltObjects,
1245  fileContext );
1246  if (!NT_SUCCESS( status )) {
1247 
1249  ("[CG] CgPostCreate: CgProcessTransaction FAILED!! \n") );
1250 
1251  goto Cleanup;
1252  }
1253  }
1254 
1255 
1256 Cleanup:
1257 
1258  FltReleaseContext( fileContext );
1259 
1260  return FLT_POSTOP_FINISHED_PROCESSING;
1261 }
1262 
1263 
1264 FLT_PREOP_CALLBACK_STATUS
1266  _Inout_ PFLT_CALLBACK_DATA Data,
1267  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1268  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
1269  )
1270 /*++
1271 
1272 Routine Description:
1273 
1274  Pre-close callback. Make the file context persistent in the volatile cache.
1275  If the file is transacted, it will be synced at KTM notification callback
1276  if committed.
1277 
1278 Arguments:
1279 
1280  Data - Pointer to the filter callbackData that is passed to us.
1281 
1282  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1283  opaque handles to this filter, instance, its associated volume and
1284  file object.
1285 
1286  CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or
1287  FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to
1288  the corresponding post-operation callback routine. Otherwise, it must be NULL.
1289 
1290 Return Value:
1291 
1292  The return value is the status of the operation.
1293 
1294 --*/
1295 {
1296 
1297  NTSTATUS status;
1298  PCG_FILE_CONTEXT fileContext = NULL;
1299 
1300  UNREFERENCED_PARAMETER( Data );
1301  UNREFERENCED_PARAMETER( CompletionContext );
1302 
1303  PAGED_CODE();
1304 
1305  status = FltGetFileContext( FltObjects->Instance,
1306  FltObjects->FileObject,
1307  &fileContext );
1308 
1309  if (!NT_SUCCESS( status )) {
1310 
1312  ("[CG] CgPreClose: find file context failed.\n") );
1313 
1314  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1315  }
1316 
1317  //
1318  // For non-transacted files,
1319  // we just print out the file is dirty or not
1320  //
1321 
1322  if ((FltObjects->Transaction == NULL) &&
1323  fileContext->Dirty) {
1324 
1326  ("[CG] CgPreClose: Non-transacted file ID %I64x,%I64x is dirty\n",
1327  fileContext->FileID.FileId64.UpperZeroes,
1328  fileContext->FileID.FileId64.Value) );
1329  }
1330 
1331  FltReleaseContext( fileContext );
1332 
1333  return FLT_PREOP_SUCCESS_NO_CALLBACK;
1334 }
1335 
1336 NTSTATUS
1338  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1339  _In_ PFLT_CONTEXT TransactionContext,
1340  _In_ ULONG TransactionNotification
1341  )
1342 /*++
1343 
1344 Routine Description:
1345 
1346  The registered routine of type PFLT_TRANSACTION_NOTIFICATION_CALLBACK
1347  in FLT_REGISTRATION structure.
1348 
1349 Arguments:
1350 
1351  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1352  opaque handles to this filter, instance, its associated volume and
1353  file object.
1354 
1355  TransactionContext - Pointer to the minifilter driver's transaction context
1356  set at PostCreate.
1357 
1358  TransactionNotification - Specifies the type of notifications that the
1359  filter manager is sending to the minifilter driver.
1360 
1361 Return Value:
1362 
1363  STATUS_SUCCESS - Returning this status value indicates that the minifilter
1364  driver is finished with the transaction. This is a success code.
1365 
1366 --*/
1367 {
1368  UNREFERENCED_PARAMETER( FltObjects );
1369 
1370  PAGED_CODE();
1371 
1373  ("[CG] CgKtmNotificationCallback: Entered\n") );
1374 
1375  FLT_ASSERTMSG("[CG] CgKtmNotificationCallback: The expected type of notifications registered at FltEnlistInTransaction(...).\n",
1376  FlagOn( TransactionNotification,
1377  (TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK) ) );
1378 
1379  if (NULL != TransactionContext) {
1380 
1381  if ( FlagOn( TransactionNotification, TRANSACTION_NOTIFY_COMMIT_FINALIZE ) ) {
1382 
1383  return CgProcessTransactionOutcome( TransactionContext, TransactionOutcomeCommitted );
1384 
1385  } else {
1386 
1387  return CgProcessTransactionOutcome( TransactionContext, TransactionOutcomeAborted );
1388  }
1389  }
1390 
1391  return STATUS_SUCCESS;
1392 }
1393 
#define IRP_MJ_WRITE
Definition: mspyLog.h:288
PFLT_FILTER gFilterInstance
Definition: change.h:36
NTSTATUS CgUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
Definition: change.c:471
CONST FLT_REGISTRATION FilterRegistration
Definition: change.c:228
#define CG_DBG_PRINT(_dbgLevel, _string)
Definition: change.h:45
CG_FILE_REFERENCE FileID
NTSTATUS CgFindOrCreateFileContext(_In_ PFLT_CALLBACK_DATA Cbd, _Outptr_ PCG_FILE_CONTEXT *FileContext)
FLT_PREOP_CALLBACK_STATUS CgPreOperationCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: change.c:956
FLT_PREOP_CALLBACK_STATUS CgPreClose(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: change.c:1265
PKTRANSACTION Transaction
FLT_POSTOP_CALLBACK_STATUS CgPostCreate(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
Definition: change.c:1157
FORCEINLINE VOID CgPropagateDirty(_Inout_ PCG_FILE_CONTEXT FileContext, _In_ ULONG TransactionOutcome)
Definition: change.c:638
NTSTATUS CgKtmNotificationCallback(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PFLT_CONTEXT TransactionContext, _In_ ULONG TransactionNotification)
Definition: change.c:1337
CONST FLT_OPERATION_REGISTRATION Callbacks[]
Definition: change.c:189
NTSTATUS CgQueryTransactionOutcome(_In_ PKTRANSACTION Transaction, _Out_ PULONG TxOutcome)
Definition: change.c:573
return TRUE
#define CGDBG_TRACE_ROUTINES
Definition: change.h:38
NTSTATUS CgInstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
Definition: change.c:299
FLT_PREOP_CALLBACK_STATUS CgPreCreate(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: change.c:1105
#define CGDBG_TRACE_DEBUG
Definition: change.h:40
DRIVER_INITIALIZE DriverEntry
Definition: change.c:53
VOID CgInstanceTeardownStart(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
Definition: change.c:341
#define IRP_MJ_SET_INFORMATION
Definition: mspyLog.h:290
#define FlagOn(_F, _SF)
Definition: minispy.h:247
#define LIST_FOR_EACH_SAFE(curr, n, head)
UNREFERENCED_PARAMETER(FileObject)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NTSTATUS CgProcessPreviousTransaction(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PCG_FILE_CONTEXT FileContext)
Definition: change.c:669
#define IRP_MJ_CLOSE
Definition: mspyLog.h:286
NTSTATUS CgInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
Definition: change.c:254
PAGED_CODE()
#define IRP_MJ_FILE_SYSTEM_CONTROL
Definition: mspyLog.h:297
NTSTATUS CgProcessTransactionOutcome(_Inout_ PCG_TRANSACTION_CONTEXT TransactionContext, _In_ ULONG TransactionOutcome)
Definition: change.c:870
#define CGDBG_TRACE_ERROR
Definition: change.h:41
PCG_TRANSACTION_CONTEXT TxContext
FLT_PREOP_CALLBACK_STATUS CgPreFsControl(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: change.c:1059
NTSTATUS CgFindOrCreateTransactionContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Outptr_ PCG_TRANSACTION_CONTEXT *TransactionContext)
struct _CG_FILE_REFERENCE::@3 FileId64
BOOLEAN CgOperationsNeedDirty(_In_ PFLT_CALLBACK_DATA Data)
Definition: change.c:513
const FLT_CONTEXT_REGISTRATION ContextRegistration[]
VOID CgInstanceTeardownComplete(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
Definition: change.c:375
#define IRP_MJ_CREATE
Definition: mspyLog.h:284

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com