WDK Mini Filter Example
delete.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1999 - 2002 Microsoft Corporation
4 
5 Module Name:
6 
7  delete.c
8 
9 Abstract:
10 
11  This is the main file for the delete detection sample minifilter.
12 
13 
14 Environment:
15 
16  Kernel mode
17 
18 
19 --*/
20 
21 
22 #include <fltKernel.h>
23 #include <dontuse.h>
24 #include <suppress.h>
25 
26 #pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")
27 
28 
29 
30 #define DFDBG_TRACE_ERRORS 0x00000001
31 #define DFDBG_TRACE_ROUTINES 0x00000002
32 #define DFDBG_TRACE_OPERATION_STATUS 0x00000004
33 
34 #define DF_VOLUME_GUID_NAME_SIZE 48
35 
36 #define DF_INSTANCE_CONTEXT_POOL_TAG 'nIfD'
37 #define DF_STREAM_CONTEXT_POOL_TAG 'xSfD'
38 #define DF_TRANSACTION_CONTEXT_POOL_TAG 'xTfD'
39 #define DF_ERESOURCE_POOL_TAG 'sRfD'
40 #define DF_DELETE_NOTIFY_POOL_TAG 'nDfD'
41 #define DF_STRING_POOL_TAG 'rSfD'
42 
43 #define DF_CONTEXT_POOL_TYPE PagedPool
44 
45 #define DF_NOTIFICATION_MASK (TRANSACTION_NOTIFY_COMMIT_FINALIZE | \
46  TRANSACTION_NOTIFY_ROLLBACK)
47 
48 
50 // Macros //
52 
53 #define DF_PRINT( ... ) \
54  DbgPrintEx( DPFLTR_FLTMGR_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__ )
55 
56 #define DF_DBG_PRINT( _dbgLevel, ... ) \
57  (FlagOn( gTraceFlags, (_dbgLevel) ) ? \
58  DF_PRINT( __VA_ARGS__ ): \
59  (0))
60 
61 #define FlagOnAll( F, T ) \
62  (FlagOn( F, T ) == T)
63 
64 
66 // Main Globals //
68 
69 PFLT_FILTER gFilterHandle;
71 
72 
74 // ReFS Compatibility Helpers //
76 
77 //
78 // This helps us deal with ReFS 128-bit file IDs and NTFS 64-bit file IDs.
79 //
80 
81 typedef union _DF_FILE_REFERENCE {
82 
83  struct {
84  ULONGLONG Value; // The 64-bit file ID lives here.
85  ULONGLONG UpperZeroes; // In a 64-bit file ID this will be 0.
86  } FileId64;
87 
88  UCHAR FileId128[16]; // The 128-bit file ID lives here.
89 
91 
92 #define DfSizeofFileId(FID) ( \
93  ((FID).FileId64.UpperZeroes == 0ll) ? \
94  sizeof((FID).FileId64.Value) : \
95  sizeof((FID).FileId128) \
96  )
97 
98 
100 // Types //
102 
103 //
104 // This is the instance context for this minifilter, it stores the volume's
105 // GUID name.
106 //
107 
108 typedef struct _DF_INSTANCE_CONTEXT {
109 
110  //
111  // Volume GUID name.
112  //
113 
114  UNICODE_STRING VolumeGuidName;
115 
117 
118 
119 //
120 // This is the stream context for this minifilter, attached whenever a stream
121 // becomes a candidate for deletion.
122 //
123 
124 typedef struct _DF_STREAM_CONTEXT {
125 
126  //
127  // FLT_FILE_NAME_INFORMATION structure with the names for this stream
128  // and file. This is only used for printing out the opened name when
129  // notifying deletes. This will be the result of an opened query name
130  // done at the last pre-cleanup on the file/stream.
131  //
132  // Therefore, there is no requirement of maintaining the file name
133  // information (for the purposes we use it) in sync with the FltMgr name
134  // cache or the file system. This makes it okay to store it in the stream
135  // context.
136  //
137 
138  PFLT_FILE_NAME_INFORMATION NameInfo;
139 
140  //
141  // File ID, obtained from querying the file system for FileInternalInformation.
142  // If the File ID is 128 bits (as in ReFS) we get it via FileIdInformation.
143  //
144 
146 
147  //
148  // Number of SetDisp operations in flight.
149  //
150 
151  volatile LONG NumOps;
152 
153  //
154  // IsNotified == 1 means a file/stream deletion was already notified.
155  //
156 
157  volatile LONG IsNotified;
158 
159  //
160  // Whether or not we've already queried the file ID.
161  //
162 
163  BOOLEAN FileIdSet;
164 
165  //
166  // Delete Disposition for this stream.
167  //
168 
169  BOOLEAN SetDisp;
170 
171  //
172  // Delete-on-Close state for this stream.
173  //
174 
175  BOOLEAN DeleteOnClose;
176 
178 
179 
180 //
181 // This is the transaction context for this minifilter, attached at post-
182 // -cleanup when notifying a delete within a transaction.
183 //
184 
185 typedef struct _DF_TRANSACTION_CONTEXT {
186 
187  //
188  // List of DF_DELETE_NOTIFY structures representing pending delete
189  // notifications.
190  //
191 
192  LIST_ENTRY DeleteNotifyList;
193 
194  //
195  // ERESOURCE for synchronized access to the DeleteNotifyList.
196  //
197  // ERESOURCEs must be allocated from NonPagedPool. If an ERESOURCE was
198  // declared here as a direct member of a structure, instead of just a
199  // pointer, then the whole transaction context would need to be allocated
200  // out of NonPagedPool.
201  //
202  // Therefore, declaring it as a pointer and only allocating at context
203  // initialization time helps us save some NonPagedPool. This is
204  // particularly important in larger context structures.
205  //
206 
207  PERESOURCE Resource;
208 
210 
211 
212 //
213 // This structure represents pending delete notifications for files that have
214 // been deleted in an open transaction.
215 //
216 
217 typedef struct _DF_DELETE_NOTIFY {
218 
219  //
220  // Links to other DF_DELETE_NOTIFY structures in the list.
221  //
222 
223  LIST_ENTRY Links;
224 
225  //
226  // Pointer to the stream context for the deleted stream/file.
227  //
228 
229  PDF_STREAM_CONTEXT StreamContext;
230 
231  //
232  // TRUE for a deleted file, FALSE for a stream.
233  //
234 
235  BOOLEAN FileDelete;
236 
238 
239 
241 // Prototypes //
243 
244 DRIVER_INITIALIZE DriverEntry;
245 NTSTATUS
246 DriverEntry (
247  _In_ PDRIVER_OBJECT DriverObject,
248  _In_ PUNICODE_STRING RegistryPath
249  );
250 
251 NTSTATUS
252 DfUnload (
253  _In_ FLT_FILTER_UNLOAD_FLAGS Flags
254  );
255 
256 NTSTATUS
258  _In_ PCFLT_RELATED_OBJECTS FltObjects,
259  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
260  _In_ DEVICE_TYPE VolumeDeviceType,
261  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
262  );
263 
264 NTSTATUS
266  _In_ PCFLT_RELATED_OBJECTS FltObjects,
267  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
268  );
269 
270 VOID
272  _In_ PCFLT_RELATED_OBJECTS FltObjects,
273  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
274  );
275 
276 VOID
278  _In_ PCFLT_RELATED_OBJECTS FltObjects,
279  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
280  );
281 
282 NTSTATUS
284  _In_ PCFLT_RELATED_OBJECTS FltObjects
285  );
286 
287 NTSTATUS
289  _In_ FLT_CONTEXT_TYPE ContextType,
290  _Outptr_ PFLT_CONTEXT *Context
291  );
292 
293 NTSTATUS
294 DfSetContext (
295  _In_ PCFLT_RELATED_OBJECTS FltObjects,
296  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
297  _In_ FLT_CONTEXT_TYPE ContextType,
298  _In_ PFLT_CONTEXT NewContext,
299  _Outptr_opt_result_maybenull_ PFLT_CONTEXT *OldContext
300  );
301 
302 NTSTATUS
303 DfGetContext (
304  _In_ PCFLT_RELATED_OBJECTS FltObjects,
305  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
306  _In_ FLT_CONTEXT_TYPE ContextType,
307  _Outptr_ PFLT_CONTEXT *Context
308  );
309 
310 NTSTATUS
312  _In_ PCFLT_RELATED_OBJECTS FltObjects,
313  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
314  _Outptr_ _Pre_valid_ PFLT_CONTEXT *Context,
315  _In_ FLT_CONTEXT_TYPE ContextType
316  );
317 
318 VOID
320  _In_ PDF_STREAM_CONTEXT StreamContext,
321  _In_ FLT_CONTEXT_TYPE ContextType
322  );
323 
324 VOID
326  _In_ PDF_TRANSACTION_CONTEXT TransactionContext,
327  _In_ FLT_CONTEXT_TYPE ContextType
328  );
329 
330 VOID
332  _In_ PDF_INSTANCE_CONTEXT InstanceContext,
333  _In_ FLT_CONTEXT_TYPE ContextType
334  );
335 
336 NTSTATUS
338  _In_ PFLT_CALLBACK_DATA Data,
339  _Inout_ PDF_STREAM_CONTEXT StreamContext
340  );
341 
342 NTSTATUS
344  _Inout_ PUNICODE_STRING String
345  );
346 
347 VOID
349  _Inout_ PUNICODE_STRING String
350  );
351 
352 NTSTATUS
354  _In_ PFLT_CALLBACK_DATA Data,
355  _In_ PCFLT_RELATED_OBJECTS FltObjects,
356  _In_ PDF_STREAM_CONTEXT StreamContext,
357  _Out_ PUNICODE_STRING String
358  );
359 
360 NTSTATUS
362  _In_ PFLT_CALLBACK_DATA Data,
363  _In_ PCFLT_RELATED_OBJECTS FltObjects,
364  _In_ PDF_STREAM_CONTEXT StreamContext
365  );
366 
367 NTSTATUS
369  _In_ PFLT_CALLBACK_DATA Data,
370  _In_ PCFLT_RELATED_OBJECTS FltObjects,
371  _In_ PDF_STREAM_CONTEXT StreamContext,
372  _In_ BOOLEAN IsTransaction
373  );
374 
375 NTSTATUS
377  _Inout_ PDF_STREAM_CONTEXT StreamContext,
378  _Inout_ PDF_TRANSACTION_CONTEXT TransactionContext,
379  _In_ BOOLEAN FileDelete
380  );
381 
382 VOID
384  _In_ PDF_STREAM_CONTEXT StreamContext,
385  _In_ BOOLEAN IsFile,
386  _Inout_opt_ PDF_TRANSACTION_CONTEXT TransactionContext
387  );
388 
389 VOID
391  _In_ PDF_DELETE_NOTIFY DeleteNotify,
392  _In_ BOOLEAN Commit
393  );
394 
395 NTSTATUS
397  _Inout_ PFLT_CALLBACK_DATA Data,
398  _In_ PCFLT_RELATED_OBJECTS FltObjects,
399  _In_ PDF_STREAM_CONTEXT StreamContext
400  );
401 
402 FLT_PREOP_CALLBACK_STATUS
404  _Inout_ PFLT_CALLBACK_DATA Data,
405  _In_ PCFLT_RELATED_OBJECTS FltObjects,
406  _Outptr_result_maybenull_ PVOID *CompletionContext
407  );
408 
409 FLT_POSTOP_CALLBACK_STATUS
411  _Inout_ PFLT_CALLBACK_DATA Data,
412  _In_ PCFLT_RELATED_OBJECTS FltObjects,
413  _In_ PVOID CompletionContext,
414  _In_ FLT_POST_OPERATION_FLAGS Flags
415  );
416 
417 FLT_PREOP_CALLBACK_STATUS
419  _Inout_ PFLT_CALLBACK_DATA Data,
420  _In_ PCFLT_RELATED_OBJECTS FltObjects,
421  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
422  );
423 
424 FLT_POSTOP_CALLBACK_STATUS
426  _Inout_ PFLT_CALLBACK_DATA Data,
427  _In_ PCFLT_RELATED_OBJECTS FltObjects,
428  _In_ PVOID CompletionContext,
429  _In_ FLT_POST_OPERATION_FLAGS Flags
430  );
431 
432 FLT_PREOP_CALLBACK_STATUS
434  _Inout_ PFLT_CALLBACK_DATA Data,
435  _In_ PCFLT_RELATED_OBJECTS FltObjects,
436  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
437  );
438 
439 FLT_POSTOP_CALLBACK_STATUS
441  _Inout_ PFLT_CALLBACK_DATA Data,
442  _In_ PCFLT_RELATED_OBJECTS FltObjects,
443  _In_ PVOID CompletionContext,
444  _In_ FLT_POST_OPERATION_FLAGS Flags
445  );
446 
447 NTSTATUS
449  _In_ PCFLT_RELATED_OBJECTS FltObjects,
450  _In_ PDF_TRANSACTION_CONTEXT TransactionContext,
451  _In_ ULONG NotificationMask
452  );
453 
454 NTSTATUS
456  _In_ PCFLT_RELATED_OBJECTS FltObjects,
457  _Inout_ PUNICODE_STRING VolumeGuidName
458  );
459 
460 NTSTATUS
461 DfGetFileId (
462  _In_ PFLT_CALLBACK_DATA Data,
463  _Inout_ PDF_STREAM_CONTEXT StreamContext
464  );
465 
467 // Text section assignments for all routines //
469 
470 
471 #ifdef ALLOC_PRAGMA
472 #pragma alloc_text(INIT, DriverEntry)
473 #pragma alloc_text(PAGE, DfUnload)
474 #pragma alloc_text(PAGE, DfInstanceSetup)
475 #pragma alloc_text(PAGE, DfInstanceQueryTeardown)
476 #pragma alloc_text(PAGE, DfInstanceTeardownStart)
477 #pragma alloc_text(PAGE, DfInstanceTeardownComplete)
478 #pragma alloc_text(PAGE, DfSetupInstanceContext)
479 #pragma alloc_text(PAGE, DfAllocateContext)
480 #pragma alloc_text(PAGE, DfSetContext)
481 #pragma alloc_text(PAGE, DfGetContext)
482 #pragma alloc_text(PAGE, DfGetOrSetContext)
483 #pragma alloc_text(PAGE, DfStreamContextCleanupCallback)
484 #pragma alloc_text(PAGE, DfTransactionContextCleanupCallback)
485 #pragma alloc_text(PAGE, DfInstanceContextCleanupCallback)
486 #pragma alloc_text(PAGE, DfGetFileNameInformation)
487 #pragma alloc_text(PAGE, DfAllocateUnicodeString)
488 #pragma alloc_text(PAGE, DfFreeUnicodeString)
489 #pragma alloc_text(PAGE, DfBuildFileIdString)
490 #pragma alloc_text(PAGE, DfDetectDeleteByFileId)
491 #pragma alloc_text(PAGE, DfIsFileDeleted)
492 #pragma alloc_text(PAGE, DfAddTransDeleteNotify)
493 #pragma alloc_text(PAGE, DfNotifyDelete)
494 #pragma alloc_text(PAGE, DfNotifyDeleteOnTransactionEnd)
495 #pragma alloc_text(PAGE, DfProcessDelete)
496 #pragma alloc_text(PAGE, DfPreCreateCallback)
497 #pragma alloc_text(PAGE, DfPostCreateCallback)
498 #pragma alloc_text(PAGE, DfPreSetInfoCallback)
499 #pragma alloc_text(PAGE, DfPostSetInfoCallback)
500 #pragma alloc_text(PAGE, DfPreCleanupCallback)
501 #pragma alloc_text(PAGE, DfPostCleanupCallback)
502 #pragma alloc_text(PAGE, DfTransactionNotificationCallback)
503 #pragma alloc_text(PAGE, DfGetVolumeGuidName)
504 #pragma alloc_text(PAGE, DfGetFileId)
505 #endif
506 
507 
509 // Context Registration //
511 
512 CONST FLT_CONTEXT_REGISTRATION Contexts[] = {
513 
514  { FLT_INSTANCE_CONTEXT,
515  0,
517  sizeof(DF_INSTANCE_CONTEXT),
519  NULL,
520  NULL,
521  NULL },
522 
523  { FLT_STREAM_CONTEXT,
524  0,
526  sizeof(DF_STREAM_CONTEXT),
528  NULL,
529  NULL,
530  NULL },
531 
532  { FLT_TRANSACTION_CONTEXT,
533  0,
535  sizeof(DF_TRANSACTION_CONTEXT),
537  NULL,
538  NULL,
539  NULL },
540 
541  { FLT_CONTEXT_END }
542 
543 };
544 
545 
547 // Operation Registration //
549 
550 CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
551 
552  { IRP_MJ_CREATE,
553  0,
556 
558  FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,
561 
562  { IRP_MJ_CLEANUP,
563  0,
566 
567  { IRP_MJ_OPERATION_END }
568 
569 };
570 
571 
573 // Filter Registration //
575 
576 CONST FLT_REGISTRATION FilterRegistration = {
577 
578  sizeof( FLT_REGISTRATION ), // Size
579  FLT_REGISTRATION_VERSION, // Version
580  0, // Flags
581 
582  Contexts, // Context
583  Callbacks, // Operation callbacks
584 
585  DfUnload, // MiniFilterUnload
586 
587  DfInstanceSetup, // InstanceSetup
588  DfInstanceQueryTeardown, // InstanceQueryTeardown
589  DfInstanceTeardownStart, // InstanceTeardownStart
590  DfInstanceTeardownComplete, // InstanceTeardownComplete
591  NULL, // GenerateFileName
592  NULL, // NormalizeNameComponent
593  NULL, // NormalizeContextCleanup
594  DfTransactionNotificationCallback, // TransactionNotification
595  NULL // NormalizeNameComponentEx
596 
597 };
598 
599 
601 // MiniFilter initialization and unload routines //
603 
604 NTSTATUS
606  _In_ PDRIVER_OBJECT DriverObject,
607  _In_ PUNICODE_STRING RegistryPath
608  )
609 /*++
610 
611 Routine Description:
612 
613  This is the initialization routine for this miniFilter driver. This
614  registers with FltMgr and initializes all global data structures.
615 
616 Arguments:
617 
618  DriverObject - Pointer to driver object created by the system to
619  represent this driver.
620 
621  RegistryPath - Unicode string identifying where the parameters for this
622  driver are located in the registry.
623 
624 Return Value:
625 
626  Returns STATUS_SUCCESS.
627 
628 --*/
629 {
630  NTSTATUS status;
631 
632  UNREFERENCED_PARAMETER( RegistryPath );
633 
635  "delete!DriverEntry: Entered\n" );
636 
637  //
638  // Default to NonPagedPoolNx for non paged pool allocations where supported.
639  //
640 
641  ExInitializeDriverRuntime( DrvRtPoolNxOptIn );
642 
643  //
644  // Register with FltMgr to tell it our callback routines
645  //
646 
647  status = FltRegisterFilter( DriverObject,
648  &FilterRegistration,
649  &gFilterHandle );
650 
651  ASSERT( NT_SUCCESS( status ) );
652 
653  if (NT_SUCCESS( status )) {
654 
655  //
656  // Start filtering i/o
657  //
658 
659  status = FltStartFiltering( gFilterHandle );
660 
661  if (!NT_SUCCESS( status )) {
662 
663  FltUnregisterFilter( gFilterHandle );
664  }
665  }
666 
667  return status;
668 }
669 
670 
671 NTSTATUS
673  _In_ FLT_FILTER_UNLOAD_FLAGS Flags
674  )
675 /*++
676 
677 Routine Description:
678 
679  This is the unload routine for this miniFilter driver. This is called
680  when the minifilter is about to be unloaded.
681 
682 Arguments:
683 
684  Flags - Indicating if this is a mandatory unload.
685 
686 Return Value:
687 
688  Returns the final status of this operation.
689 
690 --*/
691 {
692  UNREFERENCED_PARAMETER( Flags );
693 
694  PAGED_CODE();
695 
697  "delete!DfUnload: Entered\n" );
698 
699  FltUnregisterFilter( gFilterHandle );
700 
701  return STATUS_SUCCESS;
702 }
703 
704 
706 // Filter Instance Callbacks (Setup/Teardown/QueryTeardown) //
708 
709 NTSTATUS
711  _In_ PCFLT_RELATED_OBJECTS FltObjects,
712  _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
713  _In_ DEVICE_TYPE VolumeDeviceType,
714  _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
715  )
716 /*++
717 
718 Routine Description:
719 
720  This routine is called whenever a new instance is created on a volume. This
721  gives us a chance to decide if we need to attach to this volume or not.
722 
723  New instances are only created and attached to a volume if it is a writable
724  NTFS or ReFS volume.
725 
726 Arguments:
727 
728  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
729  opaque handles to this filter, instance and its associated volume.
730 
731  Flags - Flags describing the reason for this attach request.
732 
733  VolumeFilesystemType - A FLT_FSTYPE_* value indicating which file system type
734  the Filter Manager is offering to attach us to.
735 
736 Return Value:
737 
738  STATUS_SUCCESS - attach
739  STATUS_FLT_DO_NOT_ATTACH - do not attach
740 
741 --*/
742 {
743  NTSTATUS status = STATUS_SUCCESS;
744  BOOLEAN isWritable = FALSE;
745 
746  UNREFERENCED_PARAMETER( Flags );
747  UNREFERENCED_PARAMETER( VolumeDeviceType );
748 
749  PAGED_CODE();
750 
752  "delete!DfInstanceSetup: Entered\n" );
753 
754  status = FltIsVolumeWritable( FltObjects->Volume,
755  &isWritable );
756 
757  if (!NT_SUCCESS( status )) {
758 
759  return STATUS_FLT_DO_NOT_ATTACH;
760  }
761 
762  //
763  // Attaching to read-only volumes is pointless as you should not be able
764  // to delete files on such a volume.
765  //
766 
767  if (isWritable) {
768 
769  switch (VolumeFilesystemType) {
770 
771  case FLT_FSTYPE_NTFS:
772  case FLT_FSTYPE_REFS:
773 
774  status = STATUS_SUCCESS;
775  break;
776 
777  default:
778 
779  return STATUS_FLT_DO_NOT_ATTACH;
780  }
781 
782  } else {
783 
784  return STATUS_FLT_DO_NOT_ATTACH;
785  }
786 
787  return status;
788 }
789 
790 
791 NTSTATUS
793  _In_ PCFLT_RELATED_OBJECTS FltObjects,
794  _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
795  )
796 /*++
797 
798 Routine Description:
799 
800  This is called when an instance is being manually deleted by a
801  call to FltDetachVolume or FilterDetach thereby giving us a
802  chance to fail that detach request.
803 
804 Arguments:
805 
806  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
807  opaque handles to this filter, instance and its associated volume.
808 
809  Flags - Indicating where this detach request came from.
810 
811 Return Value:
812 
813  Returns the status of this operation.
814 
815 --*/
816 {
817  UNREFERENCED_PARAMETER( FltObjects );
818  UNREFERENCED_PARAMETER( Flags );
819 
820  PAGED_CODE();
821 
823  "delete!DfInstanceQueryTeardown: Entered\n" );
824 
825  return STATUS_SUCCESS;
826 }
827 
828 
829 VOID
831  _In_ PCFLT_RELATED_OBJECTS FltObjects,
832  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
833  )
834 /*++
835 
836 Routine Description:
837 
838  This routine is called at the start of instance teardown.
839 
840 Arguments:
841 
842  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
843  opaque handles to this filter, instance and its associated volume.
844 
845  Flags - Reason why this instance is been deleted.
846 
847 Return Value:
848 
849  None.
850 
851 --*/
852 {
853  UNREFERENCED_PARAMETER( FltObjects );
854  UNREFERENCED_PARAMETER( Flags );
855 
856  PAGED_CODE();
857 
859  "delete!DfInstanceTeardownStart: Entered\n" );
860 }
861 
862 
863 VOID
865  _In_ PCFLT_RELATED_OBJECTS FltObjects,
866  _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
867  )
868 /*++
869 
870 Routine Description:
871 
872  This routine is called at the end of instance teardown.
873 
874 Arguments:
875 
876  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
877  opaque handles to this filter, instance and its associated volume.
878 
879  Flags - Reason why this instance is been deleted.
880 
881 Return Value:
882 
883  None.
884 
885 --*/
886 {
887  UNREFERENCED_PARAMETER( FltObjects );
888  UNREFERENCED_PARAMETER( Flags );
889 
890  PAGED_CODE();
891 
893  "delete!DfInstanceTeardownComplete: Entered\n" );
894 }
895 
896 
898 // Context manipulation functions //
900 
901 NTSTATUS
903  _In_ FLT_CONTEXT_TYPE ContextType,
904  _Outptr_ PFLT_CONTEXT *Context
905  )
906 /*++
907 
908 Routine Description:
909 
910  This routine allocates and initializes a context of given type.
911 
912 Arguments:
913 
914  ContextType - Type of context to be allocated/initialized.
915 
916  Context - Pointer to a context pointer.
917 
918 Return Value:
919 
920  Returns a status forwarded from FltAllocateContext.
921 
922 --*/
923 {
924  NTSTATUS status;
925  PDF_TRANSACTION_CONTEXT transactionContext;
926 
927  PAGED_CODE();
928 
929  switch (ContextType) {
930 
931  case FLT_STREAM_CONTEXT:
932 
933  status = FltAllocateContext( gFilterHandle,
934  FLT_STREAM_CONTEXT,
935  sizeof(DF_STREAM_CONTEXT),
937  Context );
938 
939  if (NT_SUCCESS( status )) {
940  RtlZeroMemory( *Context, sizeof(DF_STREAM_CONTEXT) );
941  }
942 
943  return status;
944 
945  case FLT_TRANSACTION_CONTEXT:
946 
947  status = FltAllocateContext( gFilterHandle,
948  FLT_TRANSACTION_CONTEXT,
949  sizeof(DF_TRANSACTION_CONTEXT),
951  Context );
952 
953  if (NT_SUCCESS( status )) {
954  RtlZeroMemory( *Context, sizeof(DF_TRANSACTION_CONTEXT) );
955 
956  transactionContext = *Context;
957 
958  InitializeListHead( &transactionContext->DeleteNotifyList );
959 
960  transactionContext->Resource = ExAllocatePoolWithTag( NonPagedPool,
961  sizeof(ERESOURCE),
963 
964  if (NULL == transactionContext->Resource) {
965  FltReleaseContext( transactionContext );
966  return STATUS_INSUFFICIENT_RESOURCES;
967  }
968 
969  ExInitializeResourceLite( transactionContext->Resource );
970  }
971 
972  return status;
973 
974  case FLT_INSTANCE_CONTEXT:
975 
976  status = FltAllocateContext( gFilterHandle,
977  FLT_INSTANCE_CONTEXT,
978  sizeof(DF_INSTANCE_CONTEXT),
980  Context );
981 
982  if (NT_SUCCESS( status )) {
983  RtlZeroMemory( *Context, sizeof(DF_INSTANCE_CONTEXT) );
984  }
985 
986  return status;
987 
988  default:
989 
990  return STATUS_INVALID_PARAMETER;
991  }
992 }
993 
994 
995 NTSTATUS
997  _In_ PCFLT_RELATED_OBJECTS FltObjects,
998  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
999  _In_ FLT_CONTEXT_TYPE ContextType,
1000  _In_ PFLT_CONTEXT NewContext,
1001  _Outptr_opt_result_maybenull_ PFLT_CONTEXT *OldContext
1002  )
1003 /*++
1004 
1005 Routine Description:
1006 
1007  This routine sets the given context to the target.
1008 
1009 Arguments:
1010 
1011  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1012  opaque handles to this filter, instance and its associated volume.
1013 
1014  Target - Pointer to the target to which we want to attach the
1015  context. It will actually be either a FILE_OBJECT or
1016  a KTRANSACTION. For instance contexts, it's ignored, as
1017  the target is the FLT_INSTANCE itself, obtained from
1018  Data->Iopb->TargetInstance.
1019 
1020  ContextType - Type of context to get/allocate/attach. Also used to
1021  disambiguate the target/context type as this minifilter
1022  only has one type of context per target.
1023 
1024  NewContext - Pointer to the context the caller wants to attach.
1025 
1026  OldContext - Returns the context already attached to the target, if
1027  that is the case.
1028 
1029 Return Value:
1030 
1031  Returns a status forwarded from FltSetXxxContext.
1032 
1033 --*/
1034 {
1035  PAGED_CODE();
1036 
1037  switch (ContextType) {
1038 
1039  case FLT_STREAM_CONTEXT:
1040 
1041  return FltSetStreamContext( FltObjects->Instance,
1042  (PFILE_OBJECT)Target,
1043  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
1044  NewContext,
1045  OldContext );
1046 
1047  case FLT_TRANSACTION_CONTEXT:
1048 
1049  return FltSetTransactionContext( FltObjects->Instance,
1050  (PKTRANSACTION)Target,
1051  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
1052  NewContext,
1053  OldContext );
1054 
1055  case FLT_INSTANCE_CONTEXT:
1056 
1057  return FltSetInstanceContext( FltObjects->Instance,
1058  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
1059  NewContext,
1060  OldContext );
1061 
1062  default:
1063 
1064  ASSERT( !"Unexpected context type!\n" );
1065 
1066  return STATUS_INVALID_PARAMETER;
1067  }
1068 }
1069 
1070 
1071 NTSTATUS
1073  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1074  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
1075  _In_ FLT_CONTEXT_TYPE ContextType,
1076  _Outptr_ PFLT_CONTEXT *Context
1077  )
1078 /*++
1079 
1080 Routine Description:
1081 
1082  This routine gets the given context from the target.
1083 
1084 Arguments:
1085 
1086  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1087  opaque handles to this filter, instance and its associated volume.
1088 
1089  Target - Pointer to the target from which we want to obtain the
1090  context. It will actually be either a FILE_OBJECT or
1091  a KTRANSACTION. For instance contexts, it's ignored, as
1092  the target is the FLT_INSTANCE itself, obtained from
1093  Data->Iopb->TargetInstance.
1094 
1095  ContextType - Type of context to get. Also used to disambiguate
1096  the target/context type as this minifilter
1097  only has one type of context per target.
1098 
1099  Context - Pointer returning a pointer to the attached context.
1100 
1101 Return Value:
1102 
1103  Returns a status forwarded from FltSetXxxContext.
1104 
1105 --*/
1106 {
1107  PAGED_CODE();
1108 
1109  switch (ContextType) {
1110 
1111  case FLT_STREAM_CONTEXT:
1112 
1113  return FltGetStreamContext( FltObjects->Instance,
1114  (PFILE_OBJECT)Target,
1115  Context );
1116 
1117  case FLT_TRANSACTION_CONTEXT:
1118 
1119  return FltGetTransactionContext( FltObjects->Instance,
1120  (PKTRANSACTION)Target,
1121  Context );
1122 
1123  case FLT_INSTANCE_CONTEXT:
1124 
1125  return FltGetInstanceContext( FltObjects->Instance,
1126  Context );
1127 
1128  default:
1129 
1130  return STATUS_INVALID_PARAMETER;
1131  }
1132 }
1133 
1134 
1135 NTSTATUS
1137  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1138  _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target,
1139  _Outptr_ _Pre_valid_ PFLT_CONTEXT *Context,
1140  _In_ FLT_CONTEXT_TYPE ContextType
1141  )
1142 /*++
1143 
1144 Routine Description:
1145 
1146  This routine obtains a context of type ContextType that is attached to
1147  Target.
1148 
1149  If a context is already attached to Target, it will be returned in
1150  *Context. If a context is already attached, but *Context points to
1151  another context, *Context will be released.
1152 
1153  If no context is attached, and *Context points to a previously allocated
1154  context, *Context will be attached to the Target.
1155 
1156  Finally, if no previously allocated context is passed to this routine
1157  (*Context is a NULL pointer), a new Context is created and then attached
1158  to Target.
1159 
1160  In case of race conditions (or the presence of a previously allocated
1161  context at *Context), the existing attached context is returned via
1162  *Context.
1163 
1164  In case of a transaction context, this function will also enlist in the
1165  transaction.
1166 
1167 Arguments:
1168 
1169  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1170  opaque handles to this filter, instance and its associated volume.
1171 
1172  Target - Pointer to the target to which we want to attach the
1173  context. It will actually be either a FILE_OBJECT or
1174  a KTRANSACTION. It is NULL for an Instance context.
1175 
1176  Context - Pointer to a pointer to a context. Used both for
1177  returning an allocated/attached context or for receiving
1178  a context to attach to the Target.
1179 
1180  ContextType - Type of context to get/allocate/attach. Also used to
1181  disambiguate the target/context type as this minifilter
1182  only has one type of context per target.
1183 
1184 Return Value:
1185 
1186  Returns a status forwarded from Flt(((Get|Set)Xxx)|Allocate)Context or
1187  FltEnlistInTransaction.
1188 
1189 --*/
1190 {
1191  NTSTATUS status;
1192  PFLT_CONTEXT newContext;
1193  PFLT_CONTEXT oldContext;
1194 
1195  PAGED_CODE();
1196 
1197  ASSERT( NULL != Context );
1198 
1199  newContext = *Context;
1200 
1201  //
1202  // Is there already a context attached to the target?
1203  //
1204 
1205  status = DfGetContext( FltObjects,
1206  Target,
1207  ContextType,
1208  &oldContext );
1209 
1210  if (STATUS_NOT_FOUND == status) {
1211 
1212  //
1213  // There is no attached context. This means we have to either attach the
1214  // one provided by the caller or allocate a new one and attach it.
1215  //
1216 
1217  if (NULL == newContext) {
1218 
1219  //
1220  // No provided context. Allocate one.
1221  //
1222 
1223  status = DfAllocateContext( ContextType, &newContext );
1224 
1225  if (!NT_SUCCESS( status )) {
1226 
1227  //
1228  // We failed to allocate.
1229  //
1230 
1231  return status;
1232  }
1233  }
1234 
1235  } else if (!NT_SUCCESS( status )) {
1236 
1237  //
1238  // We failed trying to get a context from the target.
1239  //
1240 
1241  return status;
1242 
1243  } else {
1244 
1245  //
1246  // There is already a context attached to the target, so return
1247  // that context.
1248  //
1249  // If a context was provided by the caller, release it if it's not
1250  // the one attached to the target.
1251  //
1252 
1253  //
1254  // The caller is not allowed to set the same context on the target
1255  // twice.
1256  //
1257  ASSERT( newContext != oldContext );
1258 
1259  if (NULL != newContext) {
1260 
1261  FltReleaseContext( newContext );
1262  }
1263 
1264  *Context = oldContext;
1265  return status;
1266  }
1267 
1268  //
1269  // At this point we should have a context to set on the target (newContext).
1270  //
1271 
1272  status = DfSetContext( FltObjects,
1273  Target,
1274  ContextType,
1275  newContext,
1276  &oldContext );
1277 
1278  if (!NT_SUCCESS( status )) {
1279 
1280  //
1281  // FltSetStreamContext failed so we must release the new context.
1282  //
1283 
1284  FltReleaseContext( newContext );
1285 
1286  if (STATUS_FLT_CONTEXT_ALREADY_DEFINED == status) {
1287 
1288  //
1289  // We're racing with some other call which managed to set the
1290  // context before us. We will return that context instead, which
1291  // will be in oldContext.
1292  //
1293 
1294  *Context = oldContext;
1295  return STATUS_SUCCESS;
1296 
1297  } else {
1298 
1299  //
1300  // Failed to set the context. Return NULL.
1301  //
1302 
1303  *Context = NULL;
1304  return status;
1305  }
1306  }
1307 
1308  //
1309  // If this is setting a transaction context, we want to enlist in the
1310  // transaction as well.
1311  //
1312 
1313  if (FLT_TRANSACTION_CONTEXT == ContextType) {
1314 
1315  status = FltEnlistInTransaction( FltObjects->Instance,
1316  (PKTRANSACTION)Target,
1317  newContext,
1319 
1320  }
1321 
1322  //
1323  // Setting the context was successful so just return newContext.
1324  //
1325 
1326  *Context = newContext;
1327  return status;
1328 }
1329 
1330 
1332 // Context Cleanup Callbacks //
1334 
1335 VOID
1337  _In_ PDF_STREAM_CONTEXT StreamContext,
1338  _In_ FLT_CONTEXT_TYPE ContextType
1339  )
1340 /*++
1341 
1342 Routine Description:
1343 
1344  This routine cleans up a stream context. The only cleanup necessary is
1345  releasing the FLT_FILE_NAME_INFORMATION object of the NameInfo field.
1346 
1347 Arguments:
1348 
1349  StreamContext - Pointer to DF_STREAM_CONTEXT to be cleaned up.
1350 
1351  ContextType - Type of StreamContext. Must be FLT_STREAM_CONTEXT.
1352 
1353 --*/
1354 {
1355  UNREFERENCED_PARAMETER( ContextType );
1356 
1357  PAGED_CODE();
1358 
1359  ASSERT( ContextType == FLT_STREAM_CONTEXT );
1360 
1361  //
1362  // Release NameInfo if present.
1363  //
1364 
1365  if (StreamContext->NameInfo != NULL) {
1366 
1367  FltReleaseFileNameInformation(StreamContext->NameInfo);
1368  StreamContext->NameInfo = NULL;
1369  }
1370 }
1371 
1372 
1373 VOID
1375  _In_ PDF_TRANSACTION_CONTEXT TransactionContext,
1376  _In_ FLT_CONTEXT_TYPE ContextType
1377  )
1378 /*++
1379 
1380 Routine Description:
1381 
1382  This routine cleans up a transaction context.
1383  This operation consists basically of walking the DeleteNotifyList and
1384  deleting all the deletion notifications pending on behalf of this
1385  transaction.
1386 
1387 Arguments:
1388 
1389  TransactionContext - Pointer to DF_TRANSACTION_CONTEXT to be cleaned up.
1390 
1391  ContextType - Type of TransactionContext. Must be FLT_TRANSACTION_CONTEXT.
1392 
1393 --*/
1394 {
1395  PDF_DELETE_NOTIFY deleteNotify = NULL;
1396 
1397  UNREFERENCED_PARAMETER( ContextType );
1398 
1399  PAGED_CODE();
1400 
1401  ASSERT( ContextType == FLT_TRANSACTION_CONTEXT );
1402 
1403  if (NULL != TransactionContext->Resource) {
1404 
1405  FltAcquireResourceExclusive( TransactionContext->Resource );
1406 
1407  while (!IsListEmpty( &TransactionContext->DeleteNotifyList )) {
1408 
1409  //
1410  // Remove every DF_DELETE_NOTIFY, releasing their corresponding
1411  // FLT_FILE_NAME_INFORMATION objects and freeing pool used by
1412  // them.
1413  //
1414 
1415  deleteNotify = CONTAINING_RECORD( RemoveHeadList( &TransactionContext->DeleteNotifyList ),
1417  Links );
1418 
1419  FltReleaseContext( deleteNotify->StreamContext );
1420  ExFreePool( deleteNotify );
1421 
1422  }
1423 
1424  FltReleaseResource( TransactionContext->Resource );
1425 
1426  //
1427  // Delete and free the DeleteNotifyList synchronization resource.
1428  //
1429 
1430  ExDeleteResourceLite( TransactionContext->Resource );
1431  ExFreePool( TransactionContext->Resource );
1432  }
1433 }
1434 
1435 
1436 VOID
1438  _In_ PDF_INSTANCE_CONTEXT InstanceContext,
1439  _In_ FLT_CONTEXT_TYPE ContextType
1440  )
1441 /*++
1442 
1443 Routine Description:
1444 
1445  This routine cleans up an instance context, which consists on freeing
1446  pool used by the volume GUID name string.
1447 
1448 Arguments:
1449 
1450  InstanceContext - Pointer to DF_INSTANCE_CONTEXT to be cleaned up.
1451 
1452  ContextType - Type of InstanceContext. Must be FLT_INSTANCE_CONTEXT.
1453 
1454 --*/
1455 {
1456  UNREFERENCED_PARAMETER( ContextType );
1457 
1458  PAGED_CODE();
1459 
1460  ASSERT( ContextType == FLT_INSTANCE_CONTEXT );
1461 
1462  DfFreeUnicodeString( &InstanceContext->VolumeGuidName );
1463 }
1464 
1465 
1467 // Miscellaneous String, File Name and File ID Functions //
1469 
1470 NTSTATUS
1472  _In_ PFLT_CALLBACK_DATA Data,
1473  _Inout_ PDF_STREAM_CONTEXT StreamContext
1474  )
1475 /*++
1476 
1477 Routine Description:
1478 
1479  This routine gets and parses the file name information, obtains the File
1480  ID and saves them in the stream context.
1481 
1482 Arguments:
1483 
1484  Data - Pointer to FLT_CALLBACK_DATA.
1485 
1486  StreamContext - Pointer to stream context that will receive the file
1487  information.
1488 
1489 Return Value:
1490 
1491  Returns statuses forwarded from Flt(Get|Parse)FileNameInformation or
1492  FltQueryInformationFile.
1493 
1494 --*/
1495 {
1496  NTSTATUS status;
1497  PFLT_FILE_NAME_INFORMATION oldNameInfo;
1498  PFLT_FILE_NAME_INFORMATION newNameInfo;
1499 
1500  PAGED_CODE();
1501 
1502  //
1503  // FltGetFileNameInformation - this is enough for a file name.
1504  //
1505 
1506  status = FltGetFileNameInformation( Data,
1507  (FLT_FILE_NAME_OPENED |
1508  FLT_FILE_NAME_QUERY_DEFAULT),
1509  &newNameInfo );
1510 
1511  if (!NT_SUCCESS( status )) {
1512  return status;
1513  }
1514 
1515  //
1516  // FltParseFileNameInformation - this fills in the other gaps, like the
1517  // stream name, if present.
1518  //
1519 
1520  status = FltParseFileNameInformation( newNameInfo );
1521 
1522  if (!NT_SUCCESS( status )) {
1523  return status;
1524  }
1525 
1526  //
1527  // Now that we have a good NameInfo, set it in the context, replacing
1528  // the previous one.
1529  //
1530 
1531  oldNameInfo = InterlockedExchangePointer( &StreamContext->NameInfo,
1532  newNameInfo );
1533 
1534  if (NULL != oldNameInfo) {
1535 
1536  FltReleaseFileNameInformation( oldNameInfo );
1537  }
1538 
1539  return status;
1540 }
1541 
1542 
1543 NTSTATUS
1545  _In_ PFLT_CALLBACK_DATA Data,
1546  _Inout_ PDF_STREAM_CONTEXT StreamContext
1547  )
1548 /*++
1549 
1550 Routine Description:
1551 
1552  This routine obtains the File ID and saves it in the stream context.
1553 
1554 Arguments:
1555 
1556  Data - Pointer to FLT_CALLBACK_DATA.
1557 
1558  StreamContext - Pointer to stream context that will receive the file
1559  ID.
1560 
1561 Return Value:
1562 
1563  Returns statuses forwarded from FltQueryInformationFile, including
1564  STATUS_FILE_DELETED.
1565 
1566 --*/
1567 {
1568  NTSTATUS status = STATUS_SUCCESS;
1569  FILE_INTERNAL_INFORMATION fileInternalInformation;
1570 
1571  PAGED_CODE();
1572 
1573  //
1574  // Only query the file system for the file ID for the first time.
1575  // This is just an optimization. It doesn't need any real synchronization
1576  // because file IDs don't change.
1577  //
1578 
1579  if (!StreamContext->FileIdSet) {
1580 
1581  //
1582  // Querying for FileInternalInformation gives you the file ID.
1583  //
1584 
1585  status = FltQueryInformationFile( Data->Iopb->TargetInstance,
1586  Data->Iopb->TargetFileObject,
1587  &fileInternalInformation,
1588  sizeof(FILE_INTERNAL_INFORMATION),
1589  FileInternalInformation,
1590  NULL );
1591 
1592  if (NT_SUCCESS( status )) {
1593 
1594  //
1595  // ReFS uses 128-bit file IDs. FileInternalInformation supports 64-
1596  // bit file IDs. ReFS signals that a particular file ID can only
1597  // be represented in 128 bits by returning FILE_INVALID_FILE_ID as
1598  // the file ID. In that case we need to use FileIdInformation.
1599  //
1600 
1601  if (fileInternalInformation.IndexNumber.QuadPart == FILE_INVALID_FILE_ID) {
1602 
1603  FILE_ID_INFORMATION fileIdInformation;
1604 
1605  status = FltQueryInformationFile( Data->Iopb->TargetInstance,
1606  Data->Iopb->TargetFileObject,
1607  &fileIdInformation,
1608  sizeof(FILE_ID_INFORMATION),
1609  FileIdInformation,
1610  NULL );
1611 
1612  if (NT_SUCCESS( status )) {
1613 
1614  //
1615  // We don't use DfSizeofFileId() here because we are not
1616  // measuring the size of a DF_FILE_REFERENCE. We know we have
1617  // a 128-bit value.
1618  //
1619 
1620  RtlCopyMemory( &StreamContext->FileId,
1621  &fileIdInformation.FileId,
1622  sizeof(StreamContext->FileId) );
1623 
1624  //
1625  // Because there's (currently) no support for 128-bit values in
1626  // the compiler we need to ensure the setting of the ID and our
1627  // remembering that the file ID was set occur in the right order.
1628  //
1629 
1630  KeMemoryBarrier();
1631 
1632  StreamContext->FileIdSet = TRUE;
1633  }
1634 
1635  } else {
1636 
1637  StreamContext->FileId.FileId64.Value = fileInternalInformation.IndexNumber.QuadPart;
1638  StreamContext->FileId.FileId64.UpperZeroes = 0ll;
1639 
1640  //
1641  // Because there's (currently) no support for 128-bit values in
1642  // the compiler we need to ensure the setting of the ID and our
1643  // remembering that the file ID was set occur in the right order.
1644  //
1645 
1646  KeMemoryBarrier();
1647 
1648  StreamContext->FileIdSet = TRUE;
1649  }
1650  }
1651  }
1652 
1653  return status;
1654 }
1655 
1656 
1657 NTSTATUS
1659  _Inout_ PUNICODE_STRING String
1660  )
1661 /*++
1662 
1663 Routine Description:
1664 
1665  This helper routine simply allocates a buffer for a UNICODE_STRING and
1666  initializes its Length to zero.
1667 
1668  It uses whatever value is present in the MaximumLength field as the size
1669  for the allocation.
1670 
1671 Arguments:
1672 
1673  String - Pointer to UNICODE_STRING.
1674 
1675 Return Value:
1676 
1677  STATUS_INSUFFICIENT_RESOURCES if it was not possible to allocate the
1678  buffer from pool.
1679 
1680  STATUS_SUCCESS otherwise.
1681 
1682 --*/
1683 {
1684  PAGED_CODE();
1685 
1686  ASSERT( NULL != String );
1687  ASSERT( 0 != String->MaximumLength );
1688 
1689  String->Length = 0;
1690 
1691  String->Buffer = ExAllocatePoolWithTag( DF_CONTEXT_POOL_TYPE,
1692  String->MaximumLength,
1694 
1695  if (NULL == String->Buffer) {
1696 
1697  return STATUS_INSUFFICIENT_RESOURCES;
1698  }
1699 
1700  return STATUS_SUCCESS;
1701 }
1702 
1703 
1704 VOID
1706  _Inout_ PUNICODE_STRING String
1707  )
1708 /*++
1709 
1710 Routine Description:
1711 
1712  This helper routine frees the buffer of a UNICODE_STRING and resets its
1713  Length to zero.
1714 
1715 Arguments:
1716 
1717  String - Pointer to UNICODE_STRING.
1718 
1719 --*/
1720 {
1721  PAGED_CODE();
1722 
1723  ASSERT( NULL != String );
1724  ASSERT( 0 != String->MaximumLength );
1725 
1726  String->Length = 0;
1727 
1728  if ( NULL != String->Buffer ) {
1729 
1730  String->MaximumLength = 0;
1731  ExFreePool( String->Buffer );
1732  String->Buffer = NULL;
1733  }
1734 }
1735 
1736 
1737 NTSTATUS
1739  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1740  _Inout_ PUNICODE_STRING VolumeGuidName
1741  )
1742 /*++
1743 
1744 Routine Description:
1745 
1746  This helper routine returns a volume GUID name (with an added trailing
1747  backslash for convenience) in the VolumeGuidName string passed by the
1748  caller.
1749 
1750  The volume GUID name is cached in the instance context for the instance
1751  attached to the volume, and this function will set up an instance context
1752  with the cached name on it if there isn't one already attached to the
1753  instance.
1754 
1755 Arguments:
1756 
1757  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1758  opaque handles to this filter, instance, its associated volume and
1759  file object.
1760 
1761  VolumeGuidName - Pointer to UNICODE_STRING, returning the volume GUID name.
1762 
1763 Return Value:
1764 
1765  Return statuses forwarded by DfAllocateUnicodeString or
1766  FltGetVolumeGuidName. On error, caller needs to DfFreeUnicodeString on
1767  VolumeGuidName.
1768 
1769 --*/
1770 {
1771  NTSTATUS status;
1772  PUNICODE_STRING sourceGuidName;
1773  PDF_INSTANCE_CONTEXT instanceContext = NULL;
1774 
1775  PAGED_CODE();
1776 
1777  //
1778  // Obtain an instance context. Target is NULL for instance context, as
1779  // the FLT_INSTANCE can be obtained from the FltObjects.
1780  //
1781 
1782  status = DfGetOrSetContext( FltObjects,
1783  NULL,
1784  &instanceContext,
1785  FLT_INSTANCE_CONTEXT );
1786 
1787  if (NT_SUCCESS( status )) {
1788 
1789  //
1790  // sourceGuidName is the source from where we'll copy the volume
1791  // GUID name. Hopefully the name is present in the instance context
1792  // already (buffer is not NULL) so we'll try to use that.
1793  //
1794 
1795  sourceGuidName = &instanceContext->VolumeGuidName;
1796 
1797  if (NULL == sourceGuidName->Buffer) {
1798 
1799  //
1800  // The volume GUID name is not cached in the instance context
1801  // yet, so we will have to query the volume for it and put it
1802  // in the instance context, so future queries can get it directly
1803  // from the context.
1804  //
1805 
1806  UNICODE_STRING tempString;
1807 
1808  //
1809  // Add sizeof(WCHAR) so it's possible to add a trailing backslash here.
1810  //
1811 
1812  tempString.MaximumLength = DF_VOLUME_GUID_NAME_SIZE *
1813  sizeof(WCHAR) +
1814  sizeof(WCHAR);
1815 
1816  status = DfAllocateUnicodeString( &tempString );
1817 
1818  if (!NT_SUCCESS( status )) {
1819 
1821  "delete!%s: DfAllocateUnicodeString returned 0x%08x!\n",
1822  __FUNCTION__,
1823  status );
1824 
1825  return status;
1826  }
1827 
1828  // while there is no guid name, don't do the open by id deletion logic.
1829  // (it's actually better to defer obtaining the volume GUID name up to
1830  // the point when we actually need it, in the open by ID scenario.)
1831  status = FltGetVolumeGuidName( FltObjects->Volume,
1832  &tempString,
1833  NULL );
1834 
1835  if (!NT_SUCCESS( status )) {
1836 
1838  "delete!%s: FltGetVolumeGuidName returned 0x%08x!\n",
1839  __FUNCTION__,
1840  status );
1841 
1842  DfFreeUnicodeString( &tempString );
1843 
1844  return status;
1845  }
1846 
1847  //
1848  // Append trailing backslash.
1849  //
1850 
1851  RtlAppendUnicodeToString( &tempString, L"\\" );
1852 
1853  //
1854  // Now set the sourceGuidName to the tempString. It is okay to
1855  // set Length and MaximumLength with no synchronization because
1856  // those will always be the same value (size of a volume GUID
1857  // name with an extra trailing backslash).
1858  //
1859 
1860  sourceGuidName->Length = tempString.Length;
1861  sourceGuidName->MaximumLength = tempString.MaximumLength;
1862 
1863  //
1864  // Setting the buffer, however, requires some synchronization,
1865  // because another thread might be attempting to do the same,
1866  // and even though they're exactly the same string, they're
1867  // different allocations (buffers) so if the other thread we're
1868  // racing with manages to set the buffer before us, we need to
1869  // free our temporary string buffer.
1870  //
1871 
1872  InterlockedCompareExchangePointer( &sourceGuidName->Buffer,
1873  tempString.Buffer,
1874  NULL );
1875 
1876  if (sourceGuidName->Buffer != tempString.Buffer) {
1877 
1878  //
1879  // We didn't manage to set the buffer, so let's free the
1880  // tempString buffer.
1881  //
1882 
1883  DfFreeUnicodeString( &tempString );
1884  }
1885  }
1886 
1887  //
1888  // sourceGuidName now contains the correct GUID name, so copy that
1889  // to the caller string.
1890  //
1891 
1892  RtlCopyUnicodeString( VolumeGuidName, sourceGuidName );
1893 
1894  //
1895  // We're done with the instance context.
1896  //
1897 
1898  FltReleaseContext( instanceContext );
1899  }
1900 
1901  return status;
1902 }
1903 
1904 
1905 NTSTATUS
1907  _In_ PFLT_CALLBACK_DATA Data,
1908  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1909  _In_ PDF_STREAM_CONTEXT StreamContext,
1910  _Out_ PUNICODE_STRING String
1911  )
1912 /*++
1913 
1914 Routine Description:
1915 
1916  This helper routine builds a string used to open a file by its ID.
1917 
1918  It will assume the file ID is properly loaded in the stream context
1919  (StreamContext->FileId).
1920 
1921 Arguments:
1922 
1923  Data - Pointer to FLT_CALLBACK_DATA.
1924 
1925  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
1926  opaque handles to this filter, instance, its associated volume and
1927  file object.
1928 
1929  StreamContext - Pointer to the stream context.
1930 
1931  String - Pointer to UNICODE_STRING (output).
1932 
1933 Return Value:
1934 
1935  Return statuses forwarded by DfAllocateUnicodeString or
1936  FltGetInstanceContext.
1937 
1938 --*/
1939 {
1940  NTSTATUS status;
1941 
1942  PAGED_CODE();
1943 
1944  ASSERT( NULL != String );
1945 
1946  //
1947  // We'll compose the string with:
1948  // 1. The volume GUID name.
1949  // 2. A backslash
1950  // 3. The File ID.
1951  //
1952 
1953  //
1954  // Make sure the file ID is loaded in the StreamContext. Note that if the
1955  // file has been deleted DfGetFileId will return STATUS_FILE_DELETED.
1956  // Since we're interested in detecting whether the file has been deleted
1957  // that's fine; the open-by-ID will not actually take place. We have to
1958  // ensure it is loaded before building the string length below since we
1959  // may get either a 64-bit or 128-bit file ID back.
1960  //
1961 
1962  status = DfGetFileId( Data,
1963  StreamContext );
1964 
1965  if (!NT_SUCCESS( status )) {
1966 
1967  return status;
1968  }
1969 
1970  //
1971  // First add the lengths of 1, 2, 3 and allocate accordingly.
1972  // Note that ReFS understands both 64- and 128-bit file IDs when opening
1973  // by ID, so whichever size we get back from DfSizeofFileId will work.
1974  //
1975 
1976  String->MaximumLength = DF_VOLUME_GUID_NAME_SIZE * sizeof(WCHAR) +
1977  sizeof(WCHAR) +
1978  DfSizeofFileId( StreamContext->FileId );
1979 
1980  status = DfAllocateUnicodeString( String );
1981 
1982  if (!NT_SUCCESS( status )) {
1983 
1984  return status;
1985  }
1986 
1987  //
1988  // Now obtain the volume GUID name with a trailing backslash (1 + 2).
1989  //
1990 
1991  // obtain volume GUID name here and cache it in the InstanceContext.
1992  status = DfGetVolumeGuidName( FltObjects,
1993  String );
1994 
1995  if (!NT_SUCCESS( status )) {
1996 
1997  DfFreeUnicodeString( String );
1998 
1999  return status;
2000  }
2001 
2002  //
2003  // Now append the file ID to the end of the string.
2004  //
2005 
2006  RtlCopyMemory( Add2Ptr( String->Buffer, String->Length ),
2007  &StreamContext->FileId,
2008  DfSizeofFileId( StreamContext->FileId ));
2009 
2010  String->Length += DfSizeofFileId( StreamContext->FileId );
2011 
2012  ASSERT( String->Length == String->MaximumLength );
2013 
2014  return status;
2015 }
2016 
2017 
2018 NTSTATUS
2020  _In_ PFLT_CALLBACK_DATA Data,
2021  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2022  _In_ PDF_STREAM_CONTEXT StreamContext
2023  )
2024 /*++
2025 
2026 Routine Description:
2027 
2028  This helper routine detects a deleted file by attempting to open it using
2029  its file ID.
2030 
2031  If the file is successfully opened this routine closes the file before returning.
2032 
2033 Arguments:
2034 
2035  Data - Pointer to FLT_CALLBACK_DATA.
2036 
2037  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2038  opaque handles to this filter, instance, its associated volume and
2039  file object.
2040 
2041  StreamContext - Pointer to the stream context.
2042 
2043 Return Value:
2044 
2045  STATUS_FILE_DELETED - Returned through DfBuildFileIdString if the file has
2046  been deleted.
2047 
2048  STATUS_INVALID_PARAMETER - Returned from FltCreateFileEx2 when opening by ID
2049  a file that doesn't exist.
2050 
2051  STATUS_DELETE_PENDING - The file has been set to be deleted when the last handle
2052  goes away, but there are still open handles.
2053 
2054  Also any other NTSTATUS returned from DfBuildFileIdString, FltCreateFileEx2,
2055  or FltClose.
2056 
2057 --*/
2058 {
2059  NTSTATUS status;
2060  UNICODE_STRING fileIdString;
2061  HANDLE handle;
2062  OBJECT_ATTRIBUTES objectAttributes;
2063  IO_STATUS_BLOCK ioStatus;
2064  IO_DRIVER_CREATE_CONTEXT driverCreateContext;
2065 
2066  PAGED_CODE();
2067 
2068  //
2069  // First build the file ID string. Note that this may fail with STATUS_FILE_DELETED
2070  // and short-circuit our open-by-ID. Since we're really trying to see if
2071  // the file is deleted, that's perfectly okay.
2072  //
2073 
2074  status = DfBuildFileIdString( Data,
2075  FltObjects,
2076  StreamContext,
2077  &fileIdString );
2078 
2079  if (!NT_SUCCESS( status )) {
2080 
2081  return status;
2082  }
2083 
2084  InitializeObjectAttributes( &objectAttributes,
2085  &fileIdString,
2086  OBJ_KERNEL_HANDLE,
2087  NULL,
2088  NULL );
2089 
2090  //
2091  // It is important to initialize the IO_DRIVER_CREATE_CONTEXT structure's
2092  // TxnParameters. We'll always want to do this open on behalf of a
2093  // transaction because opening the file by ID is the method we use to
2094  // detect if the whole file still exists when we're in a transaction.
2095  //
2096 
2097  IoInitializeDriverCreateContext( &driverCreateContext );
2098  driverCreateContext.TxnParameters =
2099  IoGetTransactionParameterBlock( Data->Iopb->TargetFileObject );
2100 
2101  status = FltCreateFileEx2( gFilterHandle,
2102  Data->Iopb->TargetInstance,
2103  &handle,
2104  NULL,
2105  FILE_READ_ATTRIBUTES,
2106  &objectAttributes,
2107  &ioStatus,
2108  (PLARGE_INTEGER) NULL,
2109  0L,
2110  FILE_SHARE_VALID_FLAGS,
2111  FILE_OPEN,
2112  FILE_OPEN_REPARSE_POINT | FILE_OPEN_BY_FILE_ID,
2113  (PVOID) NULL,
2114  0L,
2115  IO_IGNORE_SHARE_ACCESS_CHECK,
2116  &driverCreateContext );
2117 
2118  if (NT_SUCCESS( status )) {
2119 
2120  status = FltClose( handle );
2121  ASSERT( NT_SUCCESS( status ) );
2122  }
2123 
2124  DfFreeUnicodeString( &fileIdString );
2125 
2126  return status;
2127 }
2128 
2129 
2131 // Deletion Verification & Processing Functions //
2133 
2134 NTSTATUS
2136  _In_ PFLT_CALLBACK_DATA Data,
2137  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2138  _In_ PDF_STREAM_CONTEXT StreamContext,
2139  _In_ BOOLEAN IsTransaction
2140  )
2141 /*++
2142 
2143 Routine Description:
2144 
2145  This routine returns whether a file was deleted. It is called from
2146  DfProcessDelete after an alternate data stream is deleted. This needs to
2147  be done for the case when the last outstanding handle to a delete-pending
2148  file is a handle to a delete-pending alternate data stream. When that
2149  handle is closed, the whole file goes away, and we want to report a whole
2150  file deletion, not just an alternate data stream deletion.
2151 
2152 Arguments:
2153 
2154  Data - Pointer to the filter callbackData that is passed to us.
2155 
2156  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2157  opaque handles to this filter, instance, its associated volume and
2158  file object.
2159 
2160  StreamContext - Pointer to the stream context.
2161 
2162  IsTransaction - TRUE if in a transaction, FALSE otherwise.
2163 
2164 Return Value:
2165 
2166  STATUS_FILE_DELETED - The whole file was deleted.
2167  Successful status - The file still exists, this was probably just a named
2168  data stream being deleted.
2169  Anything else - Failure in finding out if the file was deleted.
2170 
2171 --*/
2172 {
2173  NTSTATUS status = STATUS_SUCCESS;
2174  FILE_OBJECTID_BUFFER fileObjectIdBuf;
2175 
2176  FLT_FILESYSTEM_TYPE fileSystemType;
2177 
2178  PAGED_CODE();
2179 
2180  //
2181  // We need to know whether we're on ReFS or NTFS.
2182  //
2183 
2184  status = FltGetFileSystemType( FltObjects->Instance,
2185  &fileSystemType );
2186 
2187  if (status != STATUS_SUCCESS) {
2188 
2189  return status;
2190  }
2191 
2192  //
2193  // FSCTL_GET_OBJECT_ID does not return STATUS_FILE_DELETED if the
2194  // file was deleted in a transaction, and this is why we need another
2195  // method for detecting if the file is still present: opening by ID.
2196  //
2197  // If we're on ReFS we also need to open by file ID because ReFS does not
2198  // support object IDs.
2199  //
2200 
2201  if (IsTransaction ||
2202  (fileSystemType == FLT_FSTYPE_REFS)) {
2203 
2204  status = DfDetectDeleteByFileId( Data,
2205  FltObjects,
2206  StreamContext );
2207 
2208  switch (status) {
2209 
2210  case STATUS_INVALID_PARAMETER:
2211 
2212  //
2213  // The file was deleted. In this case, trying to open it
2214  // by ID returns STATUS_INVALID_PARAMETER.
2215  //
2216 
2217  return STATUS_FILE_DELETED;
2218 
2219  case STATUS_DELETE_PENDING:
2220 
2221  //
2222  // In this case, the main file still exists, but is in
2223  // a delete pending state, so we return STATUS_SUCCESS,
2224  // signaling it still exists and wasn't deleted by this
2225  // operation.
2226  //
2227 
2228  return STATUS_SUCCESS;
2229 
2230  default:
2231 
2232  return status;
2233  }
2234 
2235  } else {
2236 
2237  //
2238  // When not in a transaction, attempting to get the object ID of the
2239  // file is a cheaper alternative compared to opening the file by ID.
2240  //
2241 
2242  status = FltFsControlFile( Data->Iopb->TargetInstance,
2243  Data->Iopb->TargetFileObject,
2244  FSCTL_GET_OBJECT_ID,
2245  NULL,
2246  0,
2247  &fileObjectIdBuf,
2248  sizeof(FILE_OBJECTID_BUFFER),
2249  NULL );
2250 
2251  switch (status) {
2252 
2253  case STATUS_OBJECTID_NOT_FOUND:
2254 
2255  //
2256  // Getting back STATUS_OBJECTID_NOT_FOUND means the file
2257  // still exists, it just doesn't have an object ID.
2258 
2259  return STATUS_SUCCESS;
2260 
2261  default:
2262 
2263  //
2264  // Else we just get back STATUS_FILE_DELETED if the file
2265  // doesn't exist anymore, or some error status, so no
2266  // status conversion is necessary.
2267  //
2268 
2269  NOTHING;
2270  }
2271  }
2272 
2273  return status;
2274 }
2275 
2276 
2277 NTSTATUS
2279  _Inout_ PDF_STREAM_CONTEXT StreamContext,
2280  _Inout_ PDF_TRANSACTION_CONTEXT TransactionContext,
2281  _In_ BOOLEAN FileDelete
2282  )
2283 /*++
2284 
2285 Routine Description:
2286 
2287  This routine adds a pending deletion notification (DF_DELETE_NOTIFY)
2288  object to the transaction context DeleteNotifyList. It is called from
2289  DfNotifyDelete when a file or stream gets deleted in a transaction.
2290 
2291 Arguments:
2292 
2293  StreamContext - Pointer to the stream context.
2294 
2295  TransactionContext - Pointer to the transaction context.
2296 
2297  FileDelete - TRUE if this is a FILE deletion, FALSE if it's a STREAM
2298  deletion.
2299 
2300 Return Value:
2301 
2302  STATUS_SUCCESS.
2303 
2304 --*/
2305 {
2306  PDF_DELETE_NOTIFY deleteNotify;
2307 
2308  PAGED_CODE();
2309 
2310  ASSERT( NULL != TransactionContext->Resource );
2311 
2312  ASSERT( NULL != StreamContext );
2313 
2314  deleteNotify = ExAllocatePoolWithTag( DF_CONTEXT_POOL_TYPE,
2315  sizeof(DF_DELETE_NOTIFY),
2317 
2318  if (NULL == deleteNotify) {
2319 
2320  return STATUS_INSUFFICIENT_RESOURCES;
2321  }
2322 
2323  RtlZeroMemory( deleteNotify, sizeof(DF_DELETE_NOTIFY) );
2324 
2325  FltReferenceContext( StreamContext );
2326  deleteNotify->StreamContext = StreamContext;
2327  deleteNotify->FileDelete = FileDelete;
2328 
2329  FltAcquireResourceExclusive( TransactionContext->Resource );
2330 
2331  InsertTailList( &TransactionContext->DeleteNotifyList,
2332  &deleteNotify->Links );
2333 
2334  FltReleaseResource( TransactionContext->Resource );
2335 
2336  return STATUS_SUCCESS;
2337 }
2338 
2339 
2340 VOID
2342  _In_ PDF_STREAM_CONTEXT StreamContext,
2343  _In_ BOOLEAN IsFile,
2344  _Inout_opt_ PDF_TRANSACTION_CONTEXT TransactionContext
2345  )
2346 /*++
2347 
2348 Routine Description:
2349 
2350  This routine does the processing after it is verified, in the post-cleanup
2351  callback, that a file or stream were deleted. It sorts out whether it's a
2352  file or a stream delete, whether this is in a transacted context or not,
2353  and issues the appropriate notifications.
2354 
2355 Arguments:
2356 
2357  StreamContext - Pointer to the stream context of the deleted file/stream.
2358 
2359  IsFile - TRUE if deleting a file, FALSE for an alternate data stream.
2360 
2361  TransactionContext - The transaction context. Present if in a transaction,
2362  NULL otherwise.
2363 
2364 --*/
2365 {
2366  PAGED_CODE();
2367 
2368  if (InterlockedIncrement( &StreamContext->IsNotified ) <= 1) {
2369 
2370  if (IsFile) {
2371 
2373  "delete!DfPostCleanupCallback: "
2374  "A file \"%wZ\" (%p) has been",
2375  &StreamContext->NameInfo->Name,
2376  StreamContext );
2377 
2378  } else {
2379 
2381  "delete!DfPostCleanupCallback: "
2382  "An alternate data stream \"%wZ\" (%p) has been",
2383  &StreamContext->NameInfo->Name,
2384  StreamContext );
2385  }
2386 
2387  //
2388  // Flag that a delete has been notified on this file/stream.
2389  //
2390 
2391  if (NULL == TransactionContext) {
2392 
2394  " deleted!\n" );
2395 
2396  } else {
2397 
2399  " deleted in a transaction!\n" );
2400 
2401  DfAddTransDeleteNotify( StreamContext,
2402  TransactionContext,
2403  IsFile );
2404  }
2405  }
2406 }
2407 
2408 
2409 VOID
2411  _In_ PDF_DELETE_NOTIFY DeleteNotify,
2412  _In_ BOOLEAN Commit
2413  )
2414 /*++
2415 
2416 Routine Description:
2417 
2418  This routine is called by the transaction notification callback to issue
2419  the proper notifications for a file that has been deleted in the context
2420  of that transaction.
2421  The file will be reported as finally deleted, if the transaction was
2422  committed, or "saved" if the transaction was rolled back.
2423 
2424 Arguments:
2425 
2426  DeleteNotify - Pointer to the DF_DELETE_NOTIFY object that contains the
2427  data necessary for issuing this notification.
2428 
2429  Commit - TRUE if the transaction was committed, FALSE if it was
2430  rolled back.
2431 
2432 --*/
2433 {
2434  PAGED_CODE();
2435 
2436  if (DeleteNotify->FileDelete) {
2437 
2439  "delete!DfTransactionNotificationCallback: "
2440  "A file \"%wZ\" (%p) has been",
2441  &DeleteNotify->StreamContext->NameInfo->Name,
2442  DeleteNotify->StreamContext );
2443 
2444  } else {
2445 
2447  "delete!DfTransactionNotificationCallback: "
2448  "An alternate data stream \"%wZ\" (%p) has been",
2449  &DeleteNotify->StreamContext->NameInfo->Name,
2450  DeleteNotify->StreamContext );
2451  }
2452 
2453  if (Commit) {
2454 
2456  " deleted due to a transaction commit!\n" );
2457 
2458  } else {
2459 
2461  " saved due to a transaction rollback!\n" );
2462  }
2463 }
2464 
2465 
2466 NTSTATUS
2468  _Inout_ PFLT_CALLBACK_DATA Data,
2469  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2470  _In_ PDF_STREAM_CONTEXT StreamContext
2471  )
2472 /*++
2473 
2474 Routine Description:
2475 
2476  This routine does the processing after it is verified, in the post-cleanup
2477  callback, that a file or stream were deleted. It sorts out whether it's a
2478  file or a stream delete, whether this is in a transacted context or not,
2479  and issues the appropriate notifications.
2480 
2481 Arguments:
2482 
2483  Data - Pointer to the filter callbackData that is passed to us.
2484 
2485  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2486  opaque handles to this filter, instance, its associated volume and
2487  file object.
2488 
2489  StreamContext - Pointer to the stream context of the deleted file/stream.
2490 
2491 Return Value:
2492 
2493  STATUS_SUCCESS.
2494 
2495 --*/
2496 {
2497  BOOLEAN isTransaction;
2498  BOOLEAN isFileDeleted = FALSE;
2499  NTSTATUS status;
2500  PDF_TRANSACTION_CONTEXT transactionContext = NULL;
2501 
2502  PAGED_CODE();
2503 
2504  // Is this in a transacted context?
2505  isTransaction = (NULL != FltObjects->Transaction);
2506 
2507  if (isTransaction) {
2509  "delete!DfProcessDelete: In a transaction!\n" );
2510 
2511  status = DfGetOrSetContext( FltObjects,
2512  FltObjects->Transaction,
2513  &transactionContext,
2514  FLT_TRANSACTION_CONTEXT );
2515 
2516  if (!NT_SUCCESS( status )) {
2517 
2518  return status;
2519  }
2520  }
2521 
2522  //
2523  // Notify deletion. If this is an Alternate Data Stream being deleted,
2524  // check if the whole file was deleted (by calling DfIsFileDeleted) as
2525  // this could be the last handle to a delete-pending file.
2526  //
2527 
2528  status = DfIsFileDeleted( Data,
2529  FltObjects,
2530  StreamContext,
2531  isTransaction );
2532 
2533  if (STATUS_FILE_DELETED == status) {
2534 
2535  isFileDeleted = TRUE;
2536  status = STATUS_SUCCESS;
2537 
2538  } else if (!NT_SUCCESS( status )) {
2539 
2541  "delete!%s: DfIsFileDeleted returned 0x%08x!\n",
2542  __FUNCTION__,
2543  status );
2544 
2545  goto _exit;
2546  }
2547 
2548  DfNotifyDelete( StreamContext,
2549  isFileDeleted,
2550  transactionContext );
2551 
2552 _exit:
2553 
2554  if (NULL != transactionContext) {
2555 
2556  FltReleaseContext( transactionContext );
2557  }
2558 
2559  return status;
2560 }
2561 
2562 
2564 // MiniFilter Operation Callback Routines //
2566 
2567 FLT_PREOP_CALLBACK_STATUS
2569  _Inout_ PFLT_CALLBACK_DATA Data,
2570  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2571  _Outptr_result_maybenull_ PVOID *CompletionContext
2572  )
2573 /*++
2574 
2575 Routine Description:
2576 
2577  This routine is the pre-operation completion routine for
2578  IRP_MJ_CREATE in this miniFilter.
2579 
2580  In the pre-create phase we're concerned with creates with
2581  FILE_DELETE_ON_CLOSE set, and in those cases we want to flag
2582  this stream as a candidate for being deleted.
2583 
2584 Arguments:
2585 
2586  Data - Pointer to the filter callbackData that is passed to us.
2587 
2588  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2589  opaque handles to this filter, instance, its associated volume and
2590  file object.
2591 
2592  CompletionContext - The context for the completion routine for this
2593  operation.
2594 
2595 Return Value:
2596 
2597  FLT_PREOP_SUCCESS_WITH_CALLBACK - When FILE_DELETE_ON_CLOSE is set and
2598  a stream context is created.
2599 
2600  FLT_PREOP_SUCCESS_NO_CALLBACK - When FILE_DELETE_ON_CLOSE is not set
2601  and no stream context is created.
2602 
2603 --*/
2604 {
2605  PDF_STREAM_CONTEXT streamContext;
2606  NTSTATUS status;
2607 
2608  UNREFERENCED_PARAMETER( FltObjects );
2609 
2610  PAGED_CODE();
2611 
2613  "delete!DfPreCreateCallback: Entered\n" );
2614 
2615  //
2616  // Creates are only interesting in the FILE_DELETE_ON_CLOSE scenario,
2617  // in which we'll want to flag this file as a candidate for being
2618  // deleted.
2619  //
2620  // The way we do that is allocate a stream context for this and return
2621  // FLT_PREOP_SUCCESS_NO_CALLBACK, passing down the stream context via
2622  // the completion context, so that the post-create callback can, in case
2623  // of a successful create, attach this context to the stream and flag it
2624  // as a real deletion candidate.
2625  //
2626 
2627  if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_DELETE_ON_CLOSE )) {
2628 
2629  status = DfAllocateContext( FLT_STREAM_CONTEXT,
2630  &streamContext );
2631 
2632  if (NT_SUCCESS( status )) {
2633 
2634  *CompletionContext = (PVOID)streamContext;
2635 
2636  return FLT_PREOP_SYNCHRONIZE;
2637 
2638  } else {
2639 
2641  "delete!DfPreCreateCallback: An error occurred with DfAllocateStreamContext!\n" );
2642  }
2643  }
2644 
2645  *CompletionContext = NULL;
2646 
2647  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2648 }
2649 
2650 
2651 FLT_POSTOP_CALLBACK_STATUS
2653  _Inout_ PFLT_CALLBACK_DATA Data,
2654  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2655  _In_ PVOID CompletionContext,
2656  _In_ FLT_POST_OPERATION_FLAGS Flags
2657  )
2658 /*++
2659 
2660 Routine Description:
2661 
2662  This routine is the post-operation completion routine for
2663  IRP_MJ_CREATE in this miniFilter.
2664 
2665  The post-create callback will only be called when this is a create with
2666  FILE_DELETE_ON_CLOSE, meaning we have to flag it as a deletion candidate.
2667 
2668 Arguments:
2669 
2670  Data - Pointer to the filter callbackData that is passed to us.
2671 
2672  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2673  opaque handles to this filter, instance, its associated volume and
2674  file object.
2675 
2676  CompletionContext - The context for the completion routine for this
2677  operation. This will point to a DF_STREAM_CONTEXT allocated by
2678  DfPreCreateCallback, which will be used for flagging this stream
2679  as a deletion candidate.
2680 
2681 Return Value:
2682 
2683  FLT_POSTOP_FINISHED_PROCESSING - we never do any sort of asynchronous
2684  processing here.
2685 
2686 --*/
2687 {
2688  NTSTATUS status = STATUS_SUCCESS;
2689  PDF_STREAM_CONTEXT streamContext = NULL;
2690 
2691  UNREFERENCED_PARAMETER( FltObjects );
2692  UNREFERENCED_PARAMETER( Flags );
2693 
2694  PAGED_CODE();
2695 
2696  ASSERT( NULL != CompletionContext );
2697 
2698  streamContext = (PDF_STREAM_CONTEXT)CompletionContext;
2699 
2701  "delete!DfPostCreateCallback: Entered\n" );
2702 
2703  // this status check handles the draining scenario.
2704  if (NT_SUCCESS( Data->IoStatus.Status ) &&
2705  (STATUS_REPARSE != Data->IoStatus.Status)) {
2706 
2707  // assert we're not draining.
2708  ASSERT( !FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ) );
2709 
2710  //
2711  // Flag the stream as a deletion candidate: try setting the stream
2712  // context on it to the stream context allocated by DfPreCreateCallback.
2713  // If a context is already attached to the stream, DfGetOrSetContext
2714  // will do the right thing and set streamContext to it, freeing the
2715  // other context.
2716  //
2717 
2718  status = DfGetOrSetContext( FltObjects,
2719  Data->Iopb->TargetFileObject,
2720  &streamContext,
2721  FLT_STREAM_CONTEXT );
2722 
2723  if (NT_SUCCESS( status )) {
2724 
2725  //
2726  // Set DeleteOnClose on the stream context: a delete-on-close stream will
2727  // always be checked for deletion on cleanup.
2728  //
2729 
2730  streamContext->DeleteOnClose = BooleanFlagOn( Data->Iopb->Parameters.Create.Options,
2731  FILE_DELETE_ON_CLOSE );
2732  }
2733  }
2734 
2735  //
2736  // We will have a context in streamContext, because if allocation fails
2737  // in DfPreCreateCallback, FLT_PREOP_SUCCESS_NO_CALLBACK is returned, so
2738  // there is no post-create callback.
2739  //
2740  // If DfGetOrSetContext failed, if will have released streamContext
2741  // already, so only release it if status is successful.
2742  //
2743 
2744  if (NT_SUCCESS( status )) {
2745 
2746  FltReleaseContext( streamContext );
2747  }
2748 
2749  return FLT_POSTOP_FINISHED_PROCESSING;
2750 }
2751 
2752 
2753 FLT_PREOP_CALLBACK_STATUS
2755  _Inout_ PFLT_CALLBACK_DATA Data,
2756  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2757  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
2758  )
2759 /*++
2760 
2761 Routine Description:
2762 
2763  This routine is the pre-operation completion routine for
2764  IRP_MJ_SET_INFORMATION in this miniFilter.
2765 
2766  The pre-setinfo callback is important because setting
2767  FileDispositionInformation/FileDispositionInformationEx is another way of
2768  putting the file in a delete-pending state.
2769 
2770  Since the delete disposition is a reversible condition, we have to
2771  make sure to do the right thing when multiple operations are racing:
2772  we won't be able to tell the the final outcome of the delete
2773  disposition state of the stream, so everytime a race like that happens,
2774  we assume this stream as a permanent deletion candidate, so it will be
2775  checked for deletion in the post-cleanup callback.
2776 
2777 Arguments:
2778 
2779  Data - Pointer to the filter callbackData that is passed to us.
2780 
2781  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2782  opaque handles to this filter, instance, its associated volume and
2783  file object.
2784 
2785  CompletionContext - The context for the completion routine for this
2786  operation.
2787 
2788 Return Value:
2789 
2790  FLT_PREOP_SYNCHRONIZE - we never do any sort of asynchronous processing
2791  here, and we synchronize postop.
2792 
2793  FLT_PREOP_SUCCESS_NO_CALLBACK - if not FileDispositionInformation/FileDispositionInformationEx
2794  or we can't set a streamcontext.
2795 
2796 --*/
2797 {
2798  NTSTATUS status;
2799  PDF_STREAM_CONTEXT streamContext = NULL;
2800  BOOLEAN race;
2801 
2802  UNREFERENCED_PARAMETER( FltObjects );
2803 
2804  PAGED_CODE();
2805 
2806  switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) {
2807 
2808  case FileDispositionInformation:
2809  case FileDispositionInformationEx:
2810 
2811  //
2812  // We're interested when the file delete disposition changes.
2813  //
2814 
2815  status = DfGetOrSetContext( FltObjects,
2816  Data->Iopb->TargetFileObject,
2817  &streamContext,
2818  FLT_STREAM_CONTEXT );
2819 
2820  if (!NT_SUCCESS( status )) {
2821 
2822  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2823  }
2824 
2825  //
2826  // Race detection logic. The NumOps field in the StreamContext
2827  // counts the number of in-flight changes to delete disposition
2828  // on the stream.
2829  //
2830  // If there's already some operations in flight, don't bother
2831  // doing postop. Since there will be no postop, this value won't
2832  // be decremented, staying forever 2 or more, which is one of
2833  // the conditions for checking deletion at post-cleanup.
2834  //
2835 
2836  race = (InterlockedIncrement( &streamContext->NumOps ) > 1);
2837 
2838  if (!race) {
2839 
2840  //
2841  // This is the only operation in flight, so do a postop on
2842  // it because the final outcome of the delete disposition
2843  // state of the stream is deterministic.
2844  //
2845 
2846  *CompletionContext = (PVOID)streamContext;
2847 
2848  return FLT_PREOP_SYNCHRONIZE;
2849 
2850  } else {
2851 
2852  FltReleaseContext( streamContext );
2853  }
2854 
2855  // FALL_THROUGH
2856 
2857  default:
2858 
2859  return FLT_PREOP_SUCCESS_NO_CALLBACK;
2860 
2861  break;
2862  }
2863 }
2864 
2865 
2866 FLT_POSTOP_CALLBACK_STATUS
2868  _Inout_ PFLT_CALLBACK_DATA Data,
2869  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2870  _In_ PVOID CompletionContext,
2871  _In_ FLT_POST_OPERATION_FLAGS Flags
2872  )
2873 /*++
2874 
2875 Routine Description:
2876 
2877  This routine is the post-operation completion routine for
2878  IRP_MJ_SET_INFORMATION in this miniFilter.
2879 
2880  In this postop callback we will update the deletion disposition state
2881  of this stream in the stream context. This callback will only be reached
2882  when there's a single change to deletion disposition in flight for the
2883  stream or when this was the first of many racing ops to hit the preop.
2884 
2885  In the latter case, the race is already detected and adequately flagged
2886  in the other preops, so we're safe just decrementing NumOps, because the
2887  other operations will never reach postop and NumOps won't ever be
2888  decremented for them, guaranteeing that NumOps will stay nonzero forever,
2889  effectively flagging the race.
2890 
2891 Arguments:
2892 
2893  Data - Pointer to the filter callbackData that is passed to us.
2894 
2895  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
2896  opaque handles to this filter, instance, its associated volume and
2897  file object.
2898 
2899  CompletionContext - The context for the completion routine for this
2900  operation.
2901 
2902 Return Value:
2903 
2904  FLT_POSTOP_FINISHED_PROCESSING - we never do any sort of asynchronous
2905  processing here.
2906 
2907 --*/
2908 {
2909  PDF_STREAM_CONTEXT streamContext;
2910 
2911  UNREFERENCED_PARAMETER( FltObjects );
2912  UNREFERENCED_PARAMETER( Flags );
2913 
2914  PAGED_CODE();
2915 
2916  // assert on FileDispositionInformation/FileDispositionInformationEx
2917  ASSERT( (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation) ||
2918  (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformationEx) );
2919 
2920  // pass from pre-callback to post-callback
2921  ASSERT( NULL != CompletionContext );
2922  streamContext = (PDF_STREAM_CONTEXT) CompletionContext;
2923 
2924  //
2925  // Reaching a postop for FileDispositionInformation/FileDispositionInformationEx means we
2926  // MUST have a stream context passed in the CompletionContext.
2927  //
2928 
2929  if (NT_SUCCESS( Data->IoStatus.Status )) {
2930 
2931  //
2932  // No synchronization is needed to set the SetDisp field,
2933  // because in case of races, the NumOps field will be perpetually
2934  // positive, and it being positive is already an indication this
2935  // file is a delete candidate, so it will be checked at post-
2936  // -cleanup regardless of the value of SetDisp.
2937  //
2938 
2939  //
2940  // Using FileDispositinInformationEx -
2941  // FILE_DISPOSITION_ON_CLOSE controls delete on close
2942  // or set disposition behavior. It uses FILE_DISPOSITION_INFORMATION_EX structure.
2943  // FILE_DISPOSITION_ON_CLOSE is set - Set or clear DeleteOnClose
2944  // depending on FILE_DISPOSITION_DELETE flag.
2945  // FILE_DISPOSITION_ON_CLOSE is NOT set - Set or clear disposition information
2946  // depending on the flag FILE_DISPOSITION_DELETE.
2947  //
2948  //
2949  // Using FileDispositionInformation -
2950  // Controls only set disposition information behavior. It uses FILE_DISPOSITION_INFORMATION structure.
2951  //
2952 
2953  if (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformationEx) {
2954 
2955  ULONG flags = ((PFILE_DISPOSITION_INFORMATION_EX) Data->Iopb->Parameters.SetFileInformation.InfoBuffer)->Flags;
2956 
2957  if (FlagOn( flags, FILE_DISPOSITION_ON_CLOSE )) {
2958 
2959  streamContext->DeleteOnClose = BooleanFlagOn( flags, FILE_DISPOSITION_DELETE );
2960 
2961  } else {
2962 
2963  streamContext->SetDisp = BooleanFlagOn( flags, FILE_DISPOSITION_DELETE );
2964  }
2965 
2966  } else {
2967 
2968  streamContext->SetDisp = ((PFILE_DISPOSITION_INFORMATION) Data->Iopb->Parameters.SetFileInformation.InfoBuffer)->DeleteFile;
2969  }
2970  }
2971 
2972  //
2973  // Now that the operation is over, decrement NumOps.
2974  //
2975 
2976  InterlockedDecrement( &streamContext->NumOps );
2977 
2978  FltReleaseContext( streamContext );
2979 
2980  return FLT_POSTOP_FINISHED_PROCESSING;
2981 }
2982 
2983 
2984 FLT_PREOP_CALLBACK_STATUS
2986  _Inout_ PFLT_CALLBACK_DATA Data,
2987  _In_ PCFLT_RELATED_OBJECTS FltObjects,
2988  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
2989  )
2990 /*++
2991 
2992 Routine Description:
2993 
2994  This routine is the pre-operation completion routine for
2995  IRP_MJ_CLEANUP in this miniFilter.
2996 
2997  In the preop callback for cleanup, we obtain the file information and
2998  save it in the stream context, just so we have a name to use when
2999  reporting file deletions.
3000 
3001  That is done for every stream with an attached stream context because
3002  those will be deletion candidates most of the time.
3003 
3004 Arguments:
3005 
3006  Data - Pointer to the filter callbackData that is passed to us.
3007 
3008  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
3009  opaque handles to this filter, instance, its associated volume and
3010  file object.
3011 
3012  CompletionContext - The context for the completion routine for this
3013  operation.
3014 
3015 Return Value:
3016 
3017  FLT_PREOP_SYNCHRONIZE - we never do any sort of asynchronous processing
3018  here, and we want to synchronize the postop.
3019 
3020  FLT_PREOP_SUCCESS_NO_CALLBACK - when we don't manage to get a stream
3021  context.
3022 
3023 --*/
3024 {
3025  PDF_STREAM_CONTEXT streamContext;
3026  NTSTATUS status;
3027 
3028  UNREFERENCED_PARAMETER( FltObjects );
3029 
3030  PAGED_CODE();
3031 
3033  "delete!DfPreCleanupCallback: Entered\n" );
3034 
3035  status = FltGetStreamContext( Data->Iopb->TargetInstance,
3036  Data->Iopb->TargetFileObject,
3037  &streamContext );
3038 
3039  if (NT_SUCCESS( status )) {
3040 
3041  //
3042  // Only streams with stream context will be sent for deletion check
3043  // in post-cleanup, which makes sense because they would only ever
3044  // have one if they were flagged as candidates at some point.
3045  //
3046  // Gather file information here so that we have a name to report.
3047  // The name will be accurate most of the times, and in the cases it
3048  // won't, it serves as a good clue and the stream context pointer
3049  // value should offer a way to disambiguate that in case of renames
3050  // etc.
3051  //
3052 
3053  status = DfGetFileNameInformation( Data, streamContext );
3054 
3055  if (NT_SUCCESS( status )) {
3056 
3057  // pass from pre-callback to post-callback
3058  *CompletionContext = (PVOID)streamContext;
3059 
3060  return FLT_PREOP_SYNCHRONIZE;
3061 
3062  } else {
3063 
3064  FltReleaseContext( streamContext );
3065  }
3066  }
3067 
3068  return FLT_PREOP_SUCCESS_NO_CALLBACK;
3069 }
3070 
3071 
3072 FLT_POSTOP_CALLBACK_STATUS
3074  _Inout_ PFLT_CALLBACK_DATA Data,
3075  _In_ PCFLT_RELATED_OBJECTS FltObjects,
3076  _In_ PVOID CompletionContext,
3077  _In_ FLT_POST_OPERATION_FLAGS Flags
3078  )
3079 /*++
3080 
3081 Routine Description:
3082 
3083  This routine is the post-operation completion routine for
3084  IRP_MJ_CLEANUP in this miniFilter.
3085 
3086  Post-cleanup is the core of this minifilter. Here we check to see if
3087  the stream or file were deleted and report that through DbgPrint.
3088 
3089 Arguments:
3090 
3091  Data - Pointer to the filter callbackData that is passed to us.
3092 
3093  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
3094  opaque handles to this filter, instance, its associated volume and
3095  file object.
3096 
3097  CompletionContext - The completion context set in the pre-operation routine.
3098 
3099  Flags - Denotes whether the completion is successful or is being drained.
3100 
3101 Return Value:
3102 
3103  FLT_POSTOP_FINISHED_PROCESSING - we never do any sort of asynchronous
3104  processing here.
3105 
3106 --*/
3107 {
3108  FILE_STANDARD_INFORMATION fileInfo;
3109  PDF_STREAM_CONTEXT streamContext = NULL;
3110  NTSTATUS status;
3111 
3112  UNREFERENCED_PARAMETER( CompletionContext );
3113 
3114  UNREFERENCED_PARAMETER( Flags );
3115 
3116  PAGED_CODE();
3117 
3119  "delete!DfPostCleanupCallback: Entered\n" );
3120 
3121  // assert we're not draining.
3122  ASSERT( !FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ) );
3123 
3124  // pass from pre-callback to post-callback
3125  ASSERT( NULL != CompletionContext );
3126  streamContext = (PDF_STREAM_CONTEXT) CompletionContext;
3127 
3128  if (NT_SUCCESS( Data->IoStatus.Status )) {
3129 
3130  //
3131  // Determine whether or not we should check for deletion. What
3132  // flags a file as a deletion candidate is one or more of the following:
3133  //
3134  // 1. NumOps > 0. This means there are or were racing changes to
3135  // the file delete disposition state, and, in that case,
3136  // we don't know what that state is. So, let's err to the side of
3137  // caution and check if it was deleted.
3138  //
3139  // 2. SetDisp. If this is TRUE and we haven't raced in setting delete
3140  // disposition, this reflects the true delete disposition state of the
3141  // file, meaning we must check for deletes if it is set to TRUE.
3142  //
3143  // 3. DeleteOnClose. If the file was ever opened with
3144  // FILE_DELETE_ON_CLOSE, we must check to see if it was deleted.
3145  // FileDispositionInformationEx allows the this flag to be unset.
3146  //
3147  // Also, if a deletion of this stream was already notified, there is no
3148  // point notifying it again.
3149  //
3150 
3151  if (((streamContext->NumOps > 0) ||
3152  (streamContext->SetDisp) ||
3153  (streamContext->DeleteOnClose)) &&
3154  (0 == streamContext->IsNotified)) {
3155 
3156  //
3157  // The check for deletion is done via a query to
3158  // FileStandardInformation. If that returns STATUS_FILE_DELETED
3159  // it means the stream was deleted.
3160  //
3161 
3162  status = FltQueryInformationFile( Data->Iopb->TargetInstance,
3163  Data->Iopb->TargetFileObject,
3164  &fileInfo,
3165  sizeof(fileInfo),
3166  FileStandardInformation,
3167  NULL );
3168 
3169  if (STATUS_FILE_DELETED == status) {
3170 
3171  status = DfProcessDelete( Data,
3172  FltObjects,
3173  streamContext );
3174 
3175  if (!NT_SUCCESS( status )) {
3176 
3178  "delete!%s: It was not possible to verify "
3179  "deletion due to an error in DfProcessDelete (0x%08x)!\n",
3180  __FUNCTION__,
3181  status );
3182  }
3183  }
3184  }
3185  }
3186 
3187  FltReleaseContext( streamContext );
3188 
3189  return FLT_POSTOP_FINISHED_PROCESSING;
3190 }
3191 
3192 
3193 NTSTATUS
3195  _In_ PCFLT_RELATED_OBJECTS FltObjects,
3196  _In_ PDF_TRANSACTION_CONTEXT TransactionContext,
3197  _In_ ULONG NotificationMask
3198  )
3199 /*++
3200 
3201 Routine Description:
3202 
3203  This routine is the transaction notification callback for this minifilter.
3204  It is called when a transaction we're enlisted in is committed or rolled
3205  back so that it's possible to emit notifications about files that were
3206  deleted in that transaction.
3207 
3208 Arguments:
3209 
3210  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
3211  opaque handles to this filter, instance, its associated volume and
3212  file object.
3213 
3214  TransactionContext - The transaction context, set/modified when a delete
3215  is detected.
3216 
3217  NotificationMask - A mask of flags indicating the notifications received
3218  from FltMgr. Should be either TRANSACTION_NOTIFY_COMMIT or
3219  TRANSACTION_NOTIFY_ROLLBACK.
3220 
3221 Return Value:
3222 
3223  STATUS_SUCCESS - This operation is never pended.
3224 
3225 --*/
3226 {
3227  BOOLEAN commit = BooleanFlagOn( NotificationMask, TRANSACTION_NOTIFY_COMMIT_FINALIZE );
3228  PDF_DELETE_NOTIFY deleteNotify = NULL;
3229 
3230  UNREFERENCED_PARAMETER( FltObjects );
3231 
3232  PAGED_CODE();
3233 
3234  //
3235  // There is no such thing as a simultaneous commit and rollback, nor
3236  // should we get notifications for events other than a commit or a
3237  // rollback.
3238  //
3239 
3240  ASSERT( (!FlagOnAll( NotificationMask, (DF_NOTIFICATION_MASK) )) &&
3241  FlagOn( NotificationMask, (DF_NOTIFICATION_MASK) ) );
3242 
3243  if (commit) {
3244 
3246  "delete!DfTransactionNotificationCallback: COMMIT!\n" );
3247 
3248  } else {
3249 
3251  "delete!DfTransactionNotificationCallback: ROLLBACK!\n" );
3252  }
3253 
3254  ASSERT( NULL != TransactionContext->Resource );
3255 
3256  FltAcquireResourceExclusive( TransactionContext->Resource );
3257 
3258  while (!IsListEmpty( &TransactionContext->DeleteNotifyList )) {
3259 
3260  deleteNotify = CONTAINING_RECORD( RemoveHeadList( &TransactionContext->DeleteNotifyList ),
3262  Links );
3263 
3264  ASSERT( NULL != deleteNotify->StreamContext );
3265 
3266  if (!commit) {
3267  InterlockedDecrement( &deleteNotify->StreamContext->IsNotified );
3268  }
3269 
3270  DfNotifyDeleteOnTransactionEnd( deleteNotify,
3271  commit );
3272 
3273  // release stream context
3274  FltReleaseContext( deleteNotify->StreamContext );
3275  ExFreePool( deleteNotify );
3276  }
3277 
3278  FltReleaseResource( TransactionContext->Resource );
3279 
3280  return STATUS_SUCCESS;
3281 }
3282 
3283 
3284 
FLT_POSTOP_CALLBACK_STATUS DfPostCleanupCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
Definition: delete.c:3073
CONST FLT_OPERATION_REGISTRATION Callbacks[]
Definition: delete.c:550
ULONGLONG UpperZeroes
Definition: delete.c:85
BOOLEAN SetDisp
Definition: delete.c:169
NTSTATUS DfBuildFileIdString(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PDF_STREAM_CONTEXT StreamContext, _Out_ PUNICODE_STRING String)
Definition: delete.c:1906
FLT_POSTOP_CALLBACK_STATUS DfPostSetInfoCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
Definition: delete.c:2867
struct _DF_STREAM_CONTEXT DF_STREAM_CONTEXT
NTSTATUS DfGetFileId(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PDF_STREAM_CONTEXT StreamContext)
Definition: delete.c:1544
NTSTATUS DfGetVolumeGuidName(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PUNICODE_STRING VolumeGuidName)
Definition: delete.c:1738
#define DFDBG_TRACE_ROUTINES
Definition: delete.c:31
VOID DfFreeUnicodeString(_Inout_ PUNICODE_STRING String)
Definition: delete.c:1705
#define IRP_MJ_CLEANUP
Definition: mspyLog.h:302
NTSTATUS DfAddTransDeleteNotify(_Inout_ PDF_STREAM_CONTEXT StreamContext, _Inout_ PDF_TRANSACTION_CONTEXT TransactionContext, _In_ BOOLEAN FileDelete)
Definition: delete.c:2278
volatile LONG NumOps
Definition: delete.c:151
NTSTATUS DfAllocateContext(_In_ FLT_CONTEXT_TYPE ContextType, _Outptr_ PFLT_CONTEXT *Context)
Definition: delete.c:902
ULONG gTraceFlags
Definition: delete.c:70
NTSTATUS DfSetupInstanceContext(_In_ PCFLT_RELATED_OBJECTS FltObjects)
CONST FLT_REGISTRATION FilterRegistration
Definition: delete.c:576
#define DfSizeofFileId(FID)
Definition: delete.c:92
#define DF_DELETE_NOTIFY_POOL_TAG
Definition: delete.c:40
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
NTSTATUS DfProcessDelete(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PDF_STREAM_CONTEXT StreamContext)
Definition: delete.c:2467
BOOLEAN DeleteOnClose
Definition: delete.c:175
#define DFDBG_TRACE_ERRORS
Definition: delete.c:30
#define Add2Ptr(P, I)
Definition: minispy.h:238
VOID DfTransactionContextCleanupCallback(_In_ PDF_TRANSACTION_CONTEXT TransactionContext, _In_ FLT_CONTEXT_TYPE ContextType)
Definition: delete.c:1374
struct _DF_TRANSACTION_CONTEXT DF_TRANSACTION_CONTEXT
BOOLEAN FileDelete
Definition: delete.c:235
UNICODE_STRING VolumeGuidName
Definition: delete.c:114
_When_(Data==NULL, _Pre_satisfies_(FileObject !=NULL &&Instance !=NULL)) _When_(FileObject
#define DF_CONTEXT_POOL_TYPE
Definition: delete.c:43
return TRUE
union _DF_FILE_REFERENCE DF_FILE_REFERENCE
FLT_PREOP_CALLBACK_STATUS DfPreCleanupCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: delete.c:2985
#define DF_TRANSACTION_CONTEXT_POOL_TAG
Definition: delete.c:38
#define DF_NOTIFICATION_MASK
Definition: delete.c:45
#define DF_ERESOURCE_POOL_TAG
Definition: delete.c:39
FLT_PREOP_CALLBACK_STATUS DfPreCreateCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Outptr_result_maybenull_ PVOID *CompletionContext)
Definition: delete.c:2568
BOOLEAN FileIdSet
Definition: delete.c:163
NTSTATUS DfTransactionNotificationCallback(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PDF_TRANSACTION_CONTEXT TransactionContext, _In_ ULONG NotificationMask)
Definition: delete.c:3194
LIST_ENTRY DeleteNotifyList
Definition: delete.c:192
struct _DF_INSTANCE_CONTEXT * PDF_INSTANCE_CONTEXT
PFLT_FILE_NAME_INFORMATION NameInfo
Definition: delete.c:138
struct _DF_DELETE_NOTIFY DF_DELETE_NOTIFY
VOID DfInstanceContextCleanupCallback(_In_ PDF_INSTANCE_CONTEXT InstanceContext, _In_ FLT_CONTEXT_TYPE ContextType)
Definition: delete.c:1437
struct _DF_TRANSACTION_CONTEXT * PDF_TRANSACTION_CONTEXT
NTSTATUS DfInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
Definition: delete.c:710
VOID DfInstanceTeardownStart(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
Definition: delete.c:830
struct _DF_DELETE_NOTIFY * PDF_DELETE_NOTIFY
volatile LONG IsNotified
Definition: delete.c:157
union _DF_FILE_REFERENCE * PDF_FILE_REFERENCE
PERESOURCE Resource
Definition: delete.c:207
NTSTATUS DfGetOrSetContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target, _Outptr_ _Pre_valid_ PFLT_CONTEXT *Context, _In_ FLT_CONTEXT_TYPE ContextType)
Definition: delete.c:1136
struct _DF_FILE_REFERENCE::@4 FileId64
#define IRP_MJ_SET_INFORMATION
Definition: mspyLog.h:290
#define FlagOn(_F, _SF)
Definition: minispy.h:247
#define DF_DBG_PRINT(_dbgLevel,...)
Definition: delete.c:56
UCHAR FileId128[16]
Definition: delete.c:88
DF_FILE_REFERENCE FileId
Definition: delete.c:145
NTSTATUS DfGetContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target, _In_ FLT_CONTEXT_TYPE ContextType, _Outptr_ PFLT_CONTEXT *Context)
Definition: delete.c:1072
#define DF_VOLUME_GUID_NAME_SIZE
Definition: delete.c:34
UNREFERENCED_PARAMETER(FileObject)
PFLT_FILTER gFilterHandle
Definition: delete.c:69
#define DF_STRING_POOL_TAG
Definition: delete.c:41
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NTSTATUS DfUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
Definition: delete.c:672
PAGED_CODE()
DRIVER_INITIALIZE DriverEntry
Definition: delete.c:244
VOID DfStreamContextCleanupCallback(_In_ PDF_STREAM_CONTEXT StreamContext, _In_ FLT_CONTEXT_TYPE ContextType)
Definition: delete.c:1336
#define DF_STREAM_CONTEXT_POOL_TAG
Definition: delete.c:37
NTSTATUS DfIsFileDeleted(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PDF_STREAM_CONTEXT StreamContext, _In_ BOOLEAN IsTransaction)
Definition: delete.c:2135
LIST_ENTRY Links
Definition: delete.c:223
FLT_PREOP_CALLBACK_STATUS DfPreSetInfoCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: delete.c:2754
NTSTATUS DfSetContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _When_(ContextType==FLT_INSTANCE_CONTEXT, _In_opt_) _When_(ContextType!=FLT_INSTANCE_CONTEXT, _In_) PVOID Target, _In_ FLT_CONTEXT_TYPE ContextType, _In_ PFLT_CONTEXT NewContext, _Outptr_opt_result_maybenull_ PFLT_CONTEXT *OldContext)
Definition: delete.c:996
ULONGLONG Value
Definition: delete.c:84
struct _DF_STREAM_CONTEXT * PDF_STREAM_CONTEXT
NTSTATUS DfDetectDeleteByFileId(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PDF_STREAM_CONTEXT StreamContext)
Definition: delete.c:2019
VOID DfInstanceTeardownComplete(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
Definition: delete.c:864
VOID DfNotifyDeleteOnTransactionEnd(_In_ PDF_DELETE_NOTIFY DeleteNotify, _In_ BOOLEAN Commit)
Definition: delete.c:2410
NTSTATUS DfInstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
Definition: delete.c:792
PDF_STREAM_CONTEXT StreamContext
Definition: delete.c:229
NTSTATUS DfAllocateUnicodeString(_Inout_ PUNICODE_STRING String)
Definition: delete.c:1658
VOID DfNotifyDelete(_In_ PDF_STREAM_CONTEXT StreamContext, _In_ BOOLEAN IsFile, _Inout_opt_ PDF_TRANSACTION_CONTEXT TransactionContext)
Definition: delete.c:2341
CONST FLT_CONTEXT_REGISTRATION Contexts[]
Definition: delete.c:512
struct _DF_INSTANCE_CONTEXT DF_INSTANCE_CONTEXT
FLT_POSTOP_CALLBACK_STATUS DfPostCreateCallback(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
Definition: delete.c:2652
NTSTATUS DfGetFileNameInformation(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PDF_STREAM_CONTEXT StreamContext)
Definition: delete.c:1471
#define FlagOnAll(F, T)
Definition: delete.c:61
#define IRP_MJ_CREATE
Definition: mspyLog.h:284
#define DF_INSTANCE_CONTEXT_POOL_TAG
Definition: delete.c:36

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