WDK Mini Filter Example
change/context.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation. All Rights Reserved
4 
5 Module Name:
6 
7  context.c
8 
9 Abstract:
10 
11  Filter Context-related module implementation.
12 
13 Environment:
14 
15  Kernel mode
16 
17 --*/
18 
19 #include "change.h"
20 
21 //
22 // Local function prototypes.
23 //
24 
25 NTSTATUS
27  _Outptr_ PCG_FILE_CONTEXT *FileContext
28  );
29 
30 VOID
32  _In_ PFLT_CONTEXT Context,
33  _In_ FLT_CONTEXT_TYPE ContextType
34  );
35 
36 VOID
38  _In_ PFLT_CONTEXT Context,
39  _In_ FLT_CONTEXT_TYPE ContextType
40  );
41 
42 
43 #ifdef ALLOC_PRAGMA
44 #pragma alloc_text(PAGE, CgCreateFileContext)
45 #pragma alloc_text(PAGE, CgFindOrCreateFileContext)
46 #pragma alloc_text(PAGE, CgFindOrCreateTransactionContext)
47 #pragma alloc_text(PAGE, CgFileContextCleanup)
48 #pragma alloc_text(PAGE, CgTransactionContextCleanup)
49 #endif
50 
51 //
52 // Context registration structure
53 //
54 
55 const FLT_CONTEXT_REGISTRATION ContextRegistration[] = {
56 
57  { FLT_FILE_CONTEXT,
58  0,
62 
63  { FLT_TRANSACTION_CONTEXT,
64  0,
68 
69  { FLT_CONTEXT_END }
70 };
71 
72 
73 VOID
75  _In_ PFLT_CONTEXT Context,
76  _In_ FLT_CONTEXT_TYPE ContextType
77  )
78 /*++
79 
80 Routine Description:
81 
82  This routine is called whenever the file context is about to be destroyed.
83  Typically we need to clean the data structure inside it.
84 
85 Arguments:
86 
87  Context - Pointer to the PCG_FILE_CONTEXT data structure.
88 
89  ContextType - This value should be FLT_FILE_CONTEXT.
90 
91 Return Value:
92 
93  None
94 
95 --*/
96 {
97  PCG_FILE_CONTEXT fileContext = NULL;
98 
99  PAGED_CODE();
100 
101  UNREFERENCED_PARAMETER( ContextType );
102 
103  fileContext = (PCG_FILE_CONTEXT) Context;
104 
105  FLT_ASSERTMSG( "[CG]: File context is not supposed to be in the transaction context list at cleanup.!\n",
106  NULL == fileContext->TxContext );
107 
109  ("[CG]: Cleaning up file context for file ID %I64x,%I64x (FileContext = %p), dirty = %d\n",
110  fileContext->FileID.FileId64.UpperZeroes,
111  fileContext->FileID.FileId64.Value,
112  fileContext,
113  fileContext->Dirty) );
114 
116  ("[CG]: File context cleanup complete.\n") );
117 
118 
119 }
120 
121 VOID
123  _In_ PFLT_CONTEXT Context,
124  _In_ FLT_CONTEXT_TYPE ContextType
125  )
126 /*++
127 
128 Routine Description:
129 
130  This routine is called whenever the file context is about to be destroyed.
131  Typically we need to clean the data structure inside it.
132 
133 Arguments:
134 
135  Context - Pointer to the PCG_TRANSACTION_CONTEXT data structure.
136 
137  ContextType - This value should be FLT_TRANSACTION_CONTEXT.
138 
139 Return Value:
140 
141  None
142 
143 --*/
144 {
145  PCG_TRANSACTION_CONTEXT transactionContext = (PCG_TRANSACTION_CONTEXT) Context;
146 
147  PAGED_CODE();
148 
149  UNREFERENCED_PARAMETER( ContextType );
150 
152  ("[CG]: CgTransactionContextCleanup context cleanup entered.\n") );
153 
154  CgFreeMutex( transactionContext->Mutex );
155  transactionContext->Mutex = NULL;
156  ObDereferenceObject( transactionContext->Transaction );
157  transactionContext->Transaction = NULL;
158 }
159 
160 NTSTATUS
162  _In_ PFLT_INSTANCE Instance,
163  _In_ PFILE_OBJECT FileObject,
164  _Out_ PCG_FILE_REFERENCE FileId
165  )
166 /*++
167 
168 Routine Description:
169 
170  This routine gets the File ID, given a file object. It deals with both,
171  the 128-bit (ReFS) and 64-bits FileIDs.
172 
173 Arguments:
174 
175  Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL.
176 
177  FileObject - File object pointer for the file. This parameter is required and cannot be NULL.
178 
179  FileId - Pointer to file id. This is the output
180 
181 Return Value:
182 
183  Returns status forwarded from FltQueryInformationFile.
184  On success, FileId will hold the FileID for the file.
185 
186 --*/
187 {
188  NTSTATUS status = STATUS_SUCCESS;
189  FLT_FILESYSTEM_TYPE type;
190 
191  //
192  // Query for what type of filesystem we are sitting on top of.
193  //
194 
195  status = FltGetFileSystemType( Instance, &type );
196 
197  if (NT_SUCCESS( status )) {
198 
199  if (type == FLT_FSTYPE_REFS) {
200 
201  FILE_ID_INFORMATION fileIdInformation;
202 
203  status = FltQueryInformationFile( Instance,
204  FileObject,
205  &fileIdInformation,
206  sizeof(FILE_ID_INFORMATION),
207  FileIdInformation,
208  NULL );
209 
210  if (NT_SUCCESS( status )) {
211 
212  RtlCopyMemory(&FileId->FileId128, &fileIdInformation.FileId, sizeof(FileId->FileId128) );
213  }
214 
215  } else {
216 
217  FILE_INTERNAL_INFORMATION fileInternalInformation;
218 
219  status = FltQueryInformationFile( Instance,
220  FileObject,
221  &fileInternalInformation,
222  sizeof(FILE_INTERNAL_INFORMATION),
223  FileInternalInformation,
224  NULL );
225 
226  if (NT_SUCCESS( status )) {
227 
228  FileId->FileId64.Value = fileInternalInformation.IndexNumber.QuadPart;
229  FileId->FileId64.UpperZeroes = 0LL;
230  }
231  }
232  }
233 
234  return status;
235 }
236 
237 NTSTATUS
239  _In_ PFLT_CALLBACK_DATA Cbd,
240  _Outptr_ PCG_FILE_CONTEXT *FileContext
241  )
242 /*++
243 
244 Routine Description:
245 
246  This routine finds the file context for the target file.
247  If the context does not exist this routing creates
248  a new one and attaches the context to the file.
249 
250 Arguments:
251 
252  Cbd - Supplies a pointer to the callbackData which
253  declares the requested operation.
254  FileContext - Returns the file context
255 
256 Return Value:
257 
258  Status
259 
260 --*/
261 {
262  NTSTATUS status;
263  PCG_FILE_CONTEXT fileContext;
264  PCG_FILE_CONTEXT oldFileContext;
265 
266  PAGED_CODE();
267 
268  *FileContext = NULL;
269 
270  //
271  // First try to get the file context.
272  //
273 
275  ("[CG]: Trying to get file context (FileObject = %p, Instance = %p, rq = %d)\n",
276  Cbd->Iopb->TargetFileObject,
277  Cbd->Iopb->TargetInstance,
278  Cbd->Iopb->MajorFunction) );
279 
280  status = FltGetFileContext( Cbd->Iopb->TargetInstance,
281  Cbd->Iopb->TargetFileObject,
282  &fileContext );
283 
284  //
285  // If the call failed because the context does not exist
286  // and the user wants to creat a new one, then create a
287  // new context
288  //
289 
290  if (status == STATUS_NOT_FOUND) {
291 
292  CG_FILE_REFERENCE fileID;
293 
294  status = CgGetFileId( Cbd->Iopb->TargetInstance,
295  Cbd->Iopb->TargetFileObject,
296  &fileID );
297 
298  if (!NT_SUCCESS( status )) {
299 
301  ("[CG]: Failed to get file id with status 0x%x. (FileObject = %p, Instance = %p, rq = %d)\n",
302  status,
303  Cbd->Iopb->TargetFileObject,
304  Cbd->Iopb->TargetInstance,
305  Cbd->Iopb->MajorFunction) );
306 
307  return status;
308 
309  }
310 
311  //
312  // Create a file context
313  //
314 
315  status = CgCreateFileContext( &fileContext );
316 
317  if (!NT_SUCCESS( status )) {
318 
320  ("[CG]: Failed to create file context with status 0x%x. (FileObject = %p, Instance = %p)\n",
321  status,
322  Cbd->Iopb->TargetFileObject,
323  Cbd->Iopb->TargetInstance) );
324 
325  return status;
326  }
327 
328  //
329  // Initiailize fileContext
330  //
331 
332  RtlCopyMemory( &fileContext->FileID, &fileID, sizeof(fileContext->FileID) );
333 
334  //
335  // Set the new context we just allocated on the file object
336  //
337 
339  ("[CG]: Setting file context %p (FileObject = %p, Instance = %p)\n",
340  fileContext,
341  Cbd->Iopb->TargetFileObject,
342  Cbd->Iopb->TargetInstance) );
343 
344  status = FltSetFileContext( Cbd->Iopb->TargetInstance,
345  Cbd->Iopb->TargetFileObject,
346  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
347  fileContext,
348  &oldFileContext );
349 
350  if (!NT_SUCCESS( status )) {
351 
353  ("[CG]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p, rq = %d)\n",
354  status,
355  Cbd->Iopb->TargetFileObject,
356  Cbd->Iopb->TargetInstance,
357  Cbd->Iopb->MajorFunction) );
358  //
359  // We release the context here because FltSetFileContext failed
360  //
361  // If FltSetFileContext succeeded then the context will be returned
362  // to the caller. The caller will use the context and then release it
363  // when he is done with the context.
364  //
365 
367  ("[CG]: Releasing file context %p (FileObject = %p, Instance = %p)\n",
368  fileContext,
369  Cbd->Iopb->TargetFileObject,
370  Cbd->Iopb->TargetInstance) );
371 
372  FltReleaseContext( fileContext );
373 
374  if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
375 
376  //
377  // FltSetFileContext failed for a reason other than the context already
378  // existing on the file. So the object now does not have any context set
379  // on it. So we return failure to the caller.
380  //
381 
383  ("[CG]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n",
384  status,
385  Cbd->Iopb->TargetFileObject,
386  Cbd->Iopb->TargetInstance) );
387 
388  return status;
389  }
390 
391  //
392  // Race condition. Someone has set a context after we queried it.
393  // Use the already set context instead
394  //
395 
397  ("[CG]: Race: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n",
398  oldFileContext,
399  Cbd->Iopb->TargetFileObject,
400  Cbd->Iopb->TargetInstance) );
401 
402  //
403  // Return the existing context. Note that the new context that we allocated has already been
404  // realeased above.
405  //
406 
407  fileContext = oldFileContext;
408  status = STATUS_SUCCESS;
409 
410  }
411  }
412 
413  *FileContext = fileContext;
414 
415  return status;
416 }
417 
418 
419 NTSTATUS
421  _Outptr_ PCG_FILE_CONTEXT *FileContext
422  )
423 /*++
424 
425 Routine Description:
426 
427  This routine creates a new file context
428 
429 Arguments:
430 
431  FileContext - Returns the file context
432 
433 Return Value:
434 
435  Status
436 
437 --*/
438 {
439  NTSTATUS status;
440  PCG_FILE_CONTEXT fileContext;
441 
442  PAGED_CODE();
443 
444  //
445  // Allocate a file context
446  //
447 
449  ("[CG]: Allocating file context \n") );
450 
451  status = FltAllocateContext( gFilterInstance,
452  FLT_FILE_CONTEXT,
454  PagedPool,
455  &fileContext );
456 
457  if (!NT_SUCCESS( status )) {
458 
460  ("[CG]: Failed to allocate file context with status 0x%x \n",
461  status) );
462  return status;
463  }
464 
465  //
466  // Initialize the newly created context
467  //
468 
469  RtlZeroMemory(fileContext, CG_FILE_CONTEXT_SIZE);
470  *FileContext = fileContext;
471 
472  return STATUS_SUCCESS;
473 }
474 
475 NTSTATUS
477  _In_ PCFLT_RELATED_OBJECTS FltObjects,
478  _Outptr_ PCG_TRANSACTION_CONTEXT *TransactionContext
479  )
480 /*++
481 
482 Routine Description
483 
484  This routine finds the transaction context, if not found, it will
485  try to create a new one. The caller is responsible for calling
486  FltReleaseContext to decrement its reference count.
487 
488 Arguments
489 
490  FltObjects - Contains parameters required to enlist in a transaction.
491  TransactionContext - Returns the transaction context
492 
493 Return value
494 
495  Returns STATUS_SUCCESS if we were able to successfully find/create
496  a transaction context. Returns an appropriate error code on a failure.
497 
498 --*/
499 {
500  NTSTATUS status;
501  PCG_TRANSACTION_CONTEXT transactionContext = NULL;
502  PCG_TRANSACTION_CONTEXT oldTransactionContext = NULL;
503  PFAST_MUTEX pFastMutex = NULL;
504 
505  PAGED_CODE();
506 
508  ("[CG]: CgFindOrCreateTransactionContext entered. \n") );
509 
510  FLT_ASSERTMSG( "[CG]: Transaction object pointer is not supposed to be NULL !\n", FltObjects->Transaction != NULL);
511 
512  status = FltGetTransactionContext( FltObjects->Instance,
513  FltObjects->Transaction,
514  &transactionContext );
515 
516  if (NT_SUCCESS( status )) {
517 
518  *TransactionContext = transactionContext;
519  return STATUS_SUCCESS;
520  }
521 
522  if (status != STATUS_NOT_FOUND) {
523 
525  ("[CG]: Failed to get transaction context with status 0x%x \n",
526  status) );
527  return status;
528  }
529 
530  //
531  // Allocate the resource
532  //
533 
534  pFastMutex = CgAllocateMutex();
535 
536  if ( NULL == pFastMutex ) {
537 
538  return STATUS_INSUFFICIENT_RESOURCES;
539  }
540 
541  //
542  // Allocate a transaction context.
543  //
544 
545  status = FltAllocateContext( gFilterInstance,
546  FLT_TRANSACTION_CONTEXT,
548  PagedPool,
549  &transactionContext );
550 
551  if (!NT_SUCCESS( status )) {
552 
554  ("[CG]: Failed to allocate transaction context with status 0x%x \n",
555  status) );
556 
557  CgFreeMutex( pFastMutex );
558  return status;
559  }
560 
561  FLT_ASSERTMSG( "[CG]: Transaction object pointer is not supposed to be NULL !\n", FltObjects->Transaction != NULL);
562 
563  //
564  // Initialization of transaction context.
565  // The reason we allocate eResource seperately is because
566  // eResource has to be allocated in the non-paged pool.
567  //
568 
569  RtlZeroMemory(transactionContext, CG_TRANSACTION_CONTEXT_SIZE);
570  transactionContext->Mutex = pFastMutex;
571  ObReferenceObject( FltObjects->Transaction );
572  transactionContext->Transaction = FltObjects->Transaction;
573  InitializeListHead( &transactionContext->ScListHead );
574  ExInitializeFastMutex( transactionContext->Mutex );
575 
576  status = FltSetTransactionContext( FltObjects->Instance,
577  FltObjects->Transaction,
578  FLT_SET_CONTEXT_KEEP_IF_EXISTS,
579  transactionContext,
580  &oldTransactionContext );
581 
582  if (NT_SUCCESS( status )) {
583 
584  *TransactionContext = transactionContext;
585  return STATUS_SUCCESS;
586  }
587 
588 
589  FltReleaseContext( transactionContext );
590 
591  if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) {
592 
594  ("[CG]: Failed to set transaction context with status 0x%x \n",
595  status) );
596 
597  return status;
598  }
599 
600  FLT_ASSERTMSG( "[CG]: if FltSetTransactionContext returns STATUS_FLT_CONTEXT_ALREADY_DEFINED, the pointer should not be NULL.\n",
601  oldTransactionContext != NULL);
602 
603  *TransactionContext = oldTransactionContext;
604 
605 
606  return STATUS_SUCCESS;
607 }
608 
609 
#define CG_FILE_CONTEXT_TAG
PFLT_FILTER gFilterInstance
Definition: change.h:36
#define CG_TRANSACTION_CONTEXT_TAG
#define CG_DBG_PRINT(_dbgLevel, _string)
Definition: change.h:45
CG_FILE_REFERENCE FileID
NTSTATUS CgFindOrCreateFileContext(_In_ PFLT_CALLBACK_DATA Cbd, _Outptr_ PCG_FILE_CONTEXT *FileContext)
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
PKTRANSACTION Transaction
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE Instance
Definition: nc.h:493
const FLT_CONTEXT_REGISTRATION ContextRegistration[]
FORCEINLINE VOID CgFreeMutex(_In_ PFAST_MUTEX Mutex)
#define CGDBG_TRACE_ROUTINES
Definition: change.h:38
VOID CgFileContextCleanup(_In_ PFLT_CONTEXT Context, _In_ FLT_CONTEXT_TYPE ContextType)
#define CGDBG_TRACE_DEBUG
Definition: change.h:40
struct _CG_FILE_CONTEXT * PCG_FILE_CONTEXT
UNREFERENCED_PARAMETER(FileObject)
NTSTATUS CgGetFileId(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Out_ PCG_FILE_REFERENCE FileId)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
VOID CgTransactionContextCleanup(_In_ PFLT_CONTEXT Context, _In_ FLT_CONTEXT_TYPE ContextType)
PAGED_CODE()
FORCEINLINE PFAST_MUTEX CgAllocateMutex(VOID)
#define CGDBG_TRACE_ERROR
Definition: change.h:41
#define CG_FILE_CONTEXT_SIZE
#define CG_TRANSACTION_CONTEXT_SIZE
PCG_TRANSACTION_CONTEXT TxContext
NTSTATUS CgFindOrCreateTransactionContext(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Outptr_ PCG_TRANSACTION_CONTEXT *TransactionContext)
struct _CG_FILE_REFERENCE::@3 FileId64
struct _CG_TRANSACTION_CONTEXT * PCG_TRANSACTION_CONTEXT
_In_opt_ PFILE_OBJECT FileObject
Definition: nc.h:493
NTSTATUS CgCreateFileContext(_Outptr_ PCG_FILE_CONTEXT *FileContext)

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