WDK Mini Filter Example
ncdirenum.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1999 - 2002 Microsoft Corporation
4 
5 Module Name:
6 
7  ncdirenum.c
8 
9 Abstract:
10 
11  Contains routines to process user-initiated directory enumerations.
12  Depending on path, we may need to suppress the real mapping from
13  being visible to the user, or "inject" the user mapping for the
14  user. We must take care to do so having regard for the pattern
15  matching and case sensitivity dictated by the caller.
16 
17 Environment:
18 
19  Kernel mode
20 
21 --*/
22 
23 #include "nc.h"
24 
25 #ifdef ALLOC_PRAGMA
26 #pragma alloc_text(PAGE, NcCopyDirEnumEntry)
27 #pragma alloc_text(PAGE, NcDirEnumSelectNextEntry)
28 #pragma alloc_text(PAGE, NcEnumerateDirectory)
29 #pragma alloc_text(PAGE, NcEnumerateDirectorySetupInjection)
30 #pragma alloc_text(PAGE, NcEnumerateDirectoryReset)
31 #pragma alloc_text(PAGE, NcPopulateCacheEntry)
32 #pragma alloc_text(PAGE, NcSkipName)
33 #pragma alloc_text(PAGE, NcStreamHandleContextEnumClose)
34 #pragma alloc_text(PAGE, NcStreamHandleContextEnumSetup)
35 #pragma alloc_text(PAGE, NcStreamHandleContextDirEnumCreate)
36 #endif
37 
38 FLT_PREOP_CALLBACK_STATUS
40  _Inout_ PFLT_CALLBACK_DATA Data,
41  _In_ PCFLT_RELATED_OBJECTS FltObjects,
42  _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
43  )
44 /*++
45 
46 Routine Description:
47 
48  Routine is invoked when a directory enumeration is issued by the
49  user.
50 
51 Arguments:
52 
53  Data - Pointer to the filter CallbackData that is passed to us.
54 
55  FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing
56  opaque handles to this filter, instance, its associated volume and
57  file object.
58 
59  CompletionContext - The context for the completion routine for this
60  operation.
61 
62 Return Value:
63 
64  The return value is the Status of the operation.
65 
66 --*/
67 {
68  //TODO WE SHOULD CONSIDER MOVING THIS TO POST BECAUSE NTFS WILL TAKE CARE
69  // OF SYNC.
70  FLT_PREOP_CALLBACK_STATUS ReturnValue;
71  NTSTATUS Status;
72 
73  PNC_INSTANCE_CONTEXT InstanceContext = NULL;
74  PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL;
75  PNC_DIR_QRY_CONTEXT DirCtx = NULL;
76 
77  PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL;
78 
79  NC_PATH_OVERLAP RealOverlap;
80  NC_PATH_OVERLAP UserOverlap;
81 
82  BOOLEAN Reset = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN );
83  BOOLEAN FirstQuery;
84  BOOLEAN Single = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RETURN_SINGLE_ENTRY );
85  BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
86  FO_OPENED_CASE_SENSITIVE );
87 
88  FILE_INFORMATION_CLASS InformationClass =
89  Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass;
90 
91  PVOID UserBuffer;
92  ULONG BufferSize; //size for user and system buffers.
93 
94  BOOLEAN Unlock = FALSE;
95 
96  //Vars for moving data into user buffer.
97  ULONG NumEntriesCopied;
98  ULONG UserBufferOffset;
99  ULONG LastEntryStart;
100  BOOLEAN MoreRoom;
101  PNC_CACHE_ENTRY NextEntry;
102 
104 
105  BOOLEAN FoundStructureOffsets;
106 
107  UNREFERENCED_PARAMETER( CompletionContext );
108 
109  PAGED_CODE();
110 
111  FLT_ASSERT( IoGetTopLevelIrp() == NULL );
112 
113  FoundStructureOffsets = NcDetermineStructureOffsets( &Offsets,
114  InformationClass );
115 
116  if (!FoundStructureOffsets) {
117 
118  Status = STATUS_INVALID_PARAMETER;
119  ReturnValue = FLT_PREOP_COMPLETE;
120  goto NcEnumerateDirectoryCleanup;
121  }
122 
123  //
124  // Get our instance context.
125  //
126 
127  Status = FltGetInstanceContext( FltObjects->Instance,
128  &InstanceContext );
129 
130  if (!NT_SUCCESS( Status )) {
131 
132  ReturnValue = FLT_PREOP_COMPLETE;
133  goto NcEnumerateDirectoryCleanup;
134  }
135 
136  //
137  // Get the directory's name.
138  //
139 
140  Status = NcGetFileNameInformation( Data,
141  NULL,
142  NULL,
143  FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT,
144  &FileNameInformation );
145 
146  if (!NT_SUCCESS( Status )) {
147 
148  ReturnValue = FLT_PREOP_COMPLETE;
149  goto NcEnumerateDirectoryCleanup;
150  }
151 
152  Status = FltParseFileNameInformation( FileNameInformation );
153 
154  if (!NT_SUCCESS( Status )) {
155 
156  ReturnValue = FLT_PREOP_COMPLETE;
157  goto NcEnumerateDirectoryCleanup;
158  }
159 
160  //
161  // See if the directory is parent of either mapping.
162  //
163 
164  NcComparePath( &FileNameInformation->Name,
165  &InstanceContext->Mapping.UserMapping,
166  NULL,
167  IgnoreCase,
168  TRUE,
169  &UserOverlap );
170 
171  NcComparePath( &FileNameInformation->Name,
172  &InstanceContext->Mapping.RealMapping,
173  NULL,
174  IgnoreCase,
175  TRUE,
176  &RealOverlap );
177 
178  if (!(UserOverlap.Parent || RealOverlap.Parent )) {
179 
180  //
181  // We are not interested in this directory
182  // because it is not the parent of either
183  // mapping. This means we can just passthrough.
184  //
185 
186  Status = STATUS_SUCCESS;
187  ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK;
188  goto NcEnumerateDirectoryCleanup;
189  }
190 
191  Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter,
192  FltObjects->Instance,
193  FltObjects->FileObject,
194  &HandleContext );
195 
196  if (!NT_SUCCESS( Status )) {
197 
198  ReturnValue = FLT_PREOP_COMPLETE;
199  goto NcEnumerateDirectoryCleanup;
200  }
201 
202  FLT_ASSERT( HandleContext != NULL );
203 
204  DirCtx = &HandleContext->DirectoryQueryContext;
205  _Analysis_assume_( DirCtx != NULL );
206 
207  //
208  // Before looking at the context, we have to acquire the lock.
209  //
210 
211  NcLockStreamHandleContext( HandleContext );
212  Unlock = TRUE;
213 
214  //
215  // We don't allow multiple outstanding enumeration requests on
216  // a single handle.
217  //
218  // TODO: This needs to change.
219  //
220 
221  if (DirCtx->EnumerationOutstanding) {
222 
223  Status = STATUS_UNSUCCESSFUL;
224  ReturnValue = FLT_PREOP_COMPLETE;
225  goto NcEnumerateDirectoryCleanup;
226 
227  }
228 
229  DirCtx->EnumerationOutstanding = TRUE;
230 
231  //
232  // Now drop the lock. We're protected by the EnumerationOutstanding
233  // flag; nobody else can muck with the enumeration context structure.
234  //
235 
236  NcUnlockStreamHandleContext( HandleContext );
237  Unlock = FALSE;
238 
239  //
240  // Now we need to initialize or clear the cache and query options.
241  //
242 
243  Status = NcStreamHandleContextEnumSetup( DirCtx,
244  InstanceContext,
245  &Offsets,
246  Data,
247  FltObjects,
248  UserOverlap,
249  &FirstQuery );
250 
251  if (!NT_SUCCESS( Status )) {
252 
253  ReturnValue = FLT_PREOP_COMPLETE;
254  goto NcEnumerateDirectoryCleanup;
255  }
256 
257  //
258  // Prepare to populate the user buffer.
259  //
260 
261  UserBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
262 
263  BufferSize = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length;
264 
265  //
266  // Lets copy data into the user buffer.
267  //
268 
269  NumEntriesCopied = 0;
270  UserBufferOffset = 0;
271 
272  do {
273 
274  //
275  // If there is no cache entry, populate it.
276  //
277 
278  if (DirCtx->Cache.Buffer == NULL) {
279 
280  Status = NcPopulateCacheEntry( FltObjects->Instance,
281  FltObjects->FileObject,
282  Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length,
283  Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass,
284  Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName,
285  Reset,
286  &DirCtx->Cache);
287 
288  //
289  // We only want to reset the cache once.
290  //
291 
292  Reset = FALSE;
293 
294  //
295  // There was a problem populating cache, pass up to user.
296  //
297 
298  if (!NT_SUCCESS( Status )) {
299 
300  ReturnValue = FLT_PREOP_COMPLETE;
301  goto NcEnumerateDirectoryCleanup;
302  }
303 
304  }
305 
306  NextEntry = NcDirEnumSelectNextEntry( DirCtx, &Offsets, IgnoreCase );
307 
308  if (NextEntry == NULL) {
309 
310  //
311  // There are no more entries.
312  //
313 
314  break;
315  }
316 
317  if (NcSkipName( &Offsets,
318  DirCtx,
319  RealOverlap,
320  &InstanceContext->Mapping,
321  IgnoreCase )) {
322 
323  //
324  // This entry is the real mapping path. That means we have to mask it...
325  // We will say there is more room and continue.
326  //
327 
328  MoreRoom = TRUE;
329 
330  } else {
331 
332  //
333  // We are keeping this entry!
334  //
335 
336  try {
337 
338  LastEntryStart = UserBufferOffset;
339  UserBufferOffset = NcCopyDirEnumEntry( UserBuffer,
340  UserBufferOffset,
341  BufferSize,
342  NextEntry,
343  &Offsets,
344  &MoreRoom );
345 
346  } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {
347 
348  Status = STATUS_INVALID_USER_BUFFER;
349  ReturnValue = FLT_PREOP_COMPLETE;
350  goto NcEnumerateDirectoryCleanup;
351  }
352 
353  if (MoreRoom) {
354 
355  NumEntriesCopied++;
356  }
357 
358  }// end of "we are copying entry"
359 
360  } while (MoreRoom &&
361  (Single ? (NumEntriesCopied < 1) : TRUE));
362 
363  if (NumEntriesCopied > 0) {
364 
365  //
366  // Now we know what the last entry in the user buffer is going to be.
367  // Set its NextEntryOffset to 0, so that the user knows its the last element.
368  //
369 
370  try {
371 
372  NcSetNextEntryOffset( Add2Ptr(UserBuffer, LastEntryStart),
373  &Offsets,
374  TRUE );
375 
376  } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) {
377 
378  Status = STATUS_INVALID_USER_BUFFER;
379  ReturnValue = FLT_PREOP_COMPLETE;
380  goto NcEnumerateDirectoryCleanup;
381  }
382  }
383 
384  //
385  // We finished copying data.
386  //
387 
388  ReturnValue = FLT_PREOP_COMPLETE;
389 
390  if (NumEntriesCopied == 0) {
391 
392  if (FirstQuery) {
393 
394  Status = STATUS_NO_SUCH_FILE;
395 
396  } else {
397 
398  Status = STATUS_NO_MORE_FILES;
399  }
400 
401  } else {
402 
403  Status = STATUS_SUCCESS;
404  }
405 
406  ReturnValue = FLT_PREOP_COMPLETE;
407  goto NcEnumerateDirectoryCleanup;
408 
409 NcEnumerateDirectoryCleanup:
410 
411  if (ReturnValue == FLT_PREOP_COMPLETE) {
412 
413  //
414  // We need to write back results of query.
415  //
416 
417  Data->IoStatus.Status = Status;
418 
419  if (NT_SUCCESS( Status )) {
420 
421  //success
422  Data->IoStatus.Information = UserBufferOffset;
423 
424  } else {
425 
426  //failure
427  Data->IoStatus.Information = 0;
428  }
429  }
430 
431  if (InstanceContext != NULL) {
432 
433  FltReleaseContext( InstanceContext );
434  }
435 
436  if (DirCtx != NULL) {
437 
438  if (!Unlock) {
439  NcLockStreamHandleContext( HandleContext );
440  Unlock = TRUE;
441  }
442 
444  DirCtx->EnumerationOutstanding = FALSE;
445 
446  NcUnlockStreamHandleContext( HandleContext );
447  Unlock = FALSE;
448 
449  FltReleaseContext( HandleContext );
450  }
451 
452  FLT_ASSERT( !Unlock );
453 
454  if (FileNameInformation != NULL) {
455 
456  FltReleaseFileNameInformation( FileNameInformation );
457  }
458 
459  return ReturnValue;
460 }
461 
462 NTSTATUS
464  _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx,
465  _In_ PCFLT_RELATED_OBJECTS FltObjects,
466  _In_ PNC_INSTANCE_CONTEXT InstanceContext,
467  _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
468  _In_ FILE_INFORMATION_CLASS InformationClass
469  )
470 /*++
471 
472 Routine Description:
473 
474  Sets up directory enumeration context cache so that we are ready to
475  perform injection.
476 
477 Arguments:
478 
479  DirQryCtx - Pointer to directory query context (on the stream handle.)
480 
481  FltObjects - FltObjects structure for this operation.
482 
483  InstanceContext - Instance Context for this operation.
484 
485  Offsets - Offsets structure for this information class.
486 
487  InformationClass - The information class for this operation.
488 
489 Return Value:
490 
491  Returns STATUS_SUCCESS on success, otherwise an appropriate error code.
492 
493 --*/
494 {
495  NTSTATUS Status;
496 
497  OBJECT_ATTRIBUTES RealParentAttributes;
498  HANDLE RealParentHandle = 0; //close always
499  PFILE_OBJECT RealParentFileObj = NULL;
500  IO_STATUS_BLOCK RealParentStatusBlock;
501  char * QueryBuffer = NULL; //free on error, when no injection
502  ULONG QueryBufferLength = 0;
503  USHORT NameLength;
504  ULONG QueryBufferLengthRead;
505  BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
506  FO_OPENED_CASE_SENSITIVE );
507 
508  PAGED_CODE();
509 
510 
511  //
512  // If the user has specified a search string, and if our user mapping
513  // should not be returned in this search string, return success. We
514  // don't need to inject anything.
515  //
516 
517  if (DirQryCtx->SearchString.Length > 0 &&
518  !FsRtlIsNameInExpression( &DirQryCtx->SearchString,
519  &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName,
520  IgnoreCase,
521  NULL ) &&
522  !FsRtlIsNameInExpression( &DirQryCtx->SearchString,
523  &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName,
524  IgnoreCase,
525  NULL )) {
526 
527  Status = STATUS_SUCCESS;
528  goto NcEnumerateDirectorySetupCleanup;
529  }
530 
531  //
532  // Initialize insertion info.
533  //
534  // We have to insert the final component of the real mapping
535  // as the final component of the user mapping. To do this we
536  // will open the parent of the real mapping, and query the real
537  // mapping.
538  // Then we will overwrite the real mapping's name with
539  // the final component of the user mapping. This data will be
540  // stored in the DirQryCtx for later injection.
541  //
542 
543  //
544  // Open parent of real mapping.
545  //
546 
547  InitializeObjectAttributes( &RealParentAttributes,
548  &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath,
549  OBJ_KERNEL_HANDLE,
550  NULL,
551  NULL);
552 
553  Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter
554  FltObjects->Instance, // InstanceOffsets
555  &RealParentHandle, // Returned Handle
556  &RealParentFileObj, // Returned FileObject
557  FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access
558  &RealParentAttributes, // object attributes
559  &RealParentStatusBlock, // Returned IOStatusBlock
560  0, // Allocation Size
561  FILE_ATTRIBUTE_NORMAL, // File Attributes
562  0, // Share Access
563  FILE_OPEN, // Create Disposition
564  FILE_DIRECTORY_FILE, // Create Options
565  NULL, // Ea Buffer
566  0, // EA Length
567  IO_IGNORE_SHARE_ACCESS_CHECK, // Flags
568  FltObjects->FileObject ); // Transaction state
569 
570  if (!NT_SUCCESS( Status )) {
571 
572  goto NcEnumerateDirectorySetupCleanup;
573  }
574 
575  //
576  // Allocate Buffer to store mapping data.
577  //
578 
579  NameLength = Max( InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length,
580  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length );
581 
582  QueryBufferLength = Offsets->FileNameDist + NameLength;
583 
584  QueryBuffer = ExAllocatePoolWithTag( PagedPool, QueryBufferLength, NC_DIR_QRY_CACHE_TAG );
585 
586  if (QueryBuffer == NULL) {
587 
588  Status = STATUS_INSUFFICIENT_RESOURCES;
589  goto NcEnumerateDirectorySetupCleanup;
590  }
591 
592  //
593  // Query the information from the parent of the real mapping.
594  //
595 
596  Status = NcQueryDirectoryFile( FltObjects->Instance,
597  RealParentFileObj,
598  QueryBuffer,
599  QueryBufferLength,
600  InformationClass,
601  TRUE,//Return single entry
602  &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName,
603  FALSE,//restart scan
604  &QueryBufferLengthRead);
605 
606  if (Status == STATUS_NO_SUCH_FILE) {
607 
608  //
609  // The user mapping does not exist, this is allowed. It means we
610  // have nothing to inject.
611  //
612 
613  DirQryCtx->InjectionEntry.Buffer = NULL;
614  DirQryCtx->InjectionEntry.CurrentOffset = 0;
615 
616  ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG );
617  QueryBuffer = NULL;
618 
619  Status = STATUS_SUCCESS;
620 
621  } else if (!NT_SUCCESS( Status )) {
622 
623  //
624  // An unexpected error occurred, return code.
625  //
626 
627  goto NcEnumerateDirectorySetupCleanup;
628 
629  } else {
630 
631  //
632  // Now we have to munge the real mapping directory entry into a
633  // user mapping directory entry.
634  //
635 
636  NcSetFileName( QueryBuffer,
637  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer,
638  InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length,
639  Offsets,
640  TRUE );
641 
642  NcSetShortName( QueryBuffer,
643  InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Buffer,
644  InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Length,
645  Offsets );
646 
647  FLT_ASSERT( DirQryCtx->InjectionEntry.Buffer == NULL );
648 
649  //
650  // Set the injection entry up in the cache.
651  //
652 
653  DirQryCtx->InjectionEntry.Buffer = QueryBuffer;
654  DirQryCtx->InjectionEntry.CurrentOffset = 0;
655  }
656 
657 NcEnumerateDirectorySetupCleanup:
658 
659  if (!NT_SUCCESS( Status )) {
660 
661  if(QueryBuffer != NULL) {
662 
663  ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG );
664  }
665 
666  }
667 
668  if (RealParentHandle != NULL) {
669 
670  FltClose( RealParentHandle );
671  }
672 
673  if (RealParentFileObj != NULL) {
674 
675  ObDereferenceObject( RealParentFileObj );
676  }
677 
678  return Status;
679 }
680 
681 VOID
683  _Inout_ PNC_DIR_QRY_CONTEXT DirCtx
684  )
685 /*++
686 
687 Routine Description:
688 
689  Tears down any stream handle context related to enumeration and prepares
690  the stream handle context for reuse.
691 
692 Arguments:
693 
694  DirQryCtx - Pointer to directory query context (on the stream handle.)
695 
696 Return Value:
697 
698  None.
699 
700 --*/
701 {
702  PAGED_CODE();
703 
704  ExFreePoolWithTag( DirCtx->Cache.Buffer, NC_DIR_QRY_CACHE_TAG );
705  DirCtx->Cache.Buffer = NULL;
706  DirCtx->Cache.CurrentOffset = 0;
707 
708  ExFreePoolWithTag( DirCtx->InjectionEntry.Buffer, NC_DIR_QRY_CACHE_TAG );
709  DirCtx->InjectionEntry.Buffer = NULL;
710  DirCtx->InjectionEntry.CurrentOffset = 0;
711 }
712 
713 BOOLEAN
715  _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
716  _In_ PNC_DIR_QRY_CONTEXT Context,
717  _In_ NC_PATH_OVERLAP RealOverlap,
718  _In_ PNC_MAPPING Mapping,
719  _In_ BOOLEAN IgnoreCase
720  )
721 /*++
722 
723 Routine Description:
724 
725  Determines if the next entry is for the real mapping. If it is, we want
726  to "skip" returning this entry and proceed to the next.
727 
728 Arguments:
729 
730  Offsets - Offset information for this enumeration class.
731 
732  Context - Pointer to directory query context (on the stream handle.)
733  This is used to obtain the entry we are contemplating returning.
734 
735  RealOverlap - Relationship of the object that enumeration is being
736  requested on to the real mapping. This routine will only skip
737  entries if we are enumerating the parent of the real mapping.
738 
739 Return Value:
740 
741  TRUE if this entry should be skipped/suppressed; FALSE if it should be
742  returned to the user.
743 
744 --*/
745 {
746  BOOLEAN Result = FALSE;
747  PVOID CacheEntry;
748  UNICODE_STRING CacheString;
749  PUNICODE_STRING IgnoreString = &Mapping->RealMapping.LongNamePath.FinalComponentName;
750  ULONG ElementSize;
751  BOOLEAN LastElement;
752 
753  PAGED_CODE();
754 
755  if (RealOverlap.Parent) {
756 
757  //
758  // We have to check for a match.
759  //
760 
761  CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset);
762  ElementSize = NcGetEntrySize( CacheEntry, Offsets );
763  LastElement = (BOOLEAN)(NcGetNextEntryOffset( CacheEntry, Offsets ) == 0);
764 
765  CacheString.Buffer = NcGetFileName( CacheEntry, Offsets );
766  CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets );
767  CacheString.MaximumLength = CacheString.Length;
768 
769 
770  if (RtlCompareUnicodeString( &CacheString,
771  IgnoreString,
772  IgnoreCase ) == 0) {
773 
774  //
775  // We need to ignore this name.
776  //
777 
778  Result = TRUE;
779 
780  //
781  // skip
782  //
783 
784  if (LastElement) {
785 
786  //
787  // This was the last element in the entry, so we should clean the entry.
788  //
789 
790  ExFreePoolWithTag(Context->Cache.Buffer, NC_DIR_QRY_CACHE_TAG);
791  Context->Cache.Buffer = NULL;
792  Context->Cache.CurrentOffset = 0;
793 
794  } else {
795 
796  //
797  // Entry has more elements, update offset counter.
798  //
799 
800  Context->Cache.CurrentOffset += ElementSize;
801  }
802  }
803  }
804 
805  return Result;
806 }
807 
808 NTSTATUS
810  _In_ PFLT_INSTANCE Instance,
811  _In_ PFILE_OBJECT FileObject,
812  _In_ ULONG BufferLength,
813  _In_ FILE_INFORMATION_CLASS FileInfoClass,
814  _In_ PUNICODE_STRING SearchString,
815  _In_ BOOLEAN RestartScan,
816  _Out_ PNC_CACHE_ENTRY Cache
817  )
818 /*++
819 
820 Routine Description:
821 
822  Obtains the next entry from the filesystem. By always reading ahead, we
823  can determine when to return the injected entry (if one exists) while
824  attempting to preserve directory sort order.
825 
826 Arguments:
827 
828  Instance - Instance of this filter in the filter stack.
829 
830  FileObject - Directory that we are enumerating.
831 
832  BufferLength - Size, in bytes, of the buffer to allocate within this
833  routine.
834 
835  FileInfoClass - Directory enumeration class that we are using.
836 
837  SearchString - Pointer to the string containing the enumeration criteria.
838  Will be empty if enumerating all objects in a directory.
839 
840  RestartScan - Boolean value set to TRUE if we should start enumeration from
841  the beginning. Set to FALSE to continue from the previous point.
842 
843  Cache - Pointer to our structure for receiving the cached entry.
844 
845 Return Value:
846 
847  The return value is the Status of the operation.
848 
849 --*/
850 {
851 
852  NTSTATUS Status;
853  PVOID Buffer;
854 
855  PAGED_CODE();
856 
857  if (SearchString != NULL && SearchString->Buffer == NULL) {
858 
859  //
860  // In the case there is no search string provided,
861  // don't pass one to the filesystem.
862  //
863 
864  SearchString = NULL;
865  }
866 
867  Buffer = ExAllocatePoolWithTag( PagedPool, BufferLength, NC_DIR_QRY_CACHE_TAG );
868 
869  if (Buffer == NULL) {
870 
871  Status = STATUS_INSUFFICIENT_RESOURCES;
872  return Status;
873  }
874 
875  Status = NcQueryDirectoryFile( Instance,
876  FileObject,
877  Buffer,
878  BufferLength,
879  FileInfoClass,
880  FALSE,
881  SearchString,
882  RestartScan,
883  NULL);
884 
885  if (Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE) {
886 
887  //
888  // There are no more files. Keep cache empty.
889  //
890 
891  Cache->Buffer = NULL;
892  Cache->CurrentOffset = 0;
893 
894  ExFreePoolWithTag( Buffer, NC_DIR_QRY_CACHE_TAG );
895 
896  Status = STATUS_SUCCESS;
897 
898  } else if (NT_SUCCESS( Status )) {
899 
900  //
901  // There were entries, populate.
902  //
903 
904  Cache->Buffer = Buffer;
905  Cache->CurrentOffset = 0;
906 
907  } else {
908 
909  //
910  // An unspecified error occurred, return it.
911  //
912 
913  ExFreePoolWithTag( Buffer, NC_DIR_QRY_CACHE_TAG );
914  }
915 
916  return Status;
917 }
918 
921  _Inout_ PNC_DIR_QRY_CONTEXT Context,
922  _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
923  _In_ BOOLEAN IgnoreCase
924  )
925 /*++
926 
927 Routine Description:
928 
929  This routine determines whether the cached entry (returned from the
930  filesystem) should be returned now or whether the injected entry (as a
931  result of our mapping) should be returned now.
932 
933 Arguments:
934 
935  Context - The enumeration context of this handle.
936 
937  Offsets - Information describing the offsets for this enumeration class.
938 
939  IgnoreCase - TRUE if we are case insensitive, FALSE if case sensitive.
940 
941 Return Value:
942 
943  A pointer to the entry we should return, or NULL if there is nothing
944  remaining to return.
945 
946 --*/
947 {
948  PNC_CACHE_ENTRY NextEntry;
949  UNICODE_STRING CacheString;
950  UNICODE_STRING InsertString;
951  PVOID CacheEntry;
952  PVOID InjectEntry;
953 
954  PAGED_CODE();
955 
956  //
957  // Figure out which name comes first
958  //
959 
960  if ((Context->Cache.Buffer == NULL) &&
961  (Context->InjectionEntry.Buffer == NULL)) {
962 
963  //
964  // There are no names left, return STATUS_NO_MORE_FILES
965  //
966 
967  NextEntry = NULL;
968 
969  } else if (Context->Cache.Buffer == NULL) {
970 
971  //
972  // The cache is empty, so inject.
973  //
974 
975  NextEntry = &Context->InjectionEntry;
976 
977  } else if (Context->InjectionEntry.Buffer == NULL) {
978 
979  //
980  // The injection entry is empty, drain the cache.
981  //
982 
983  NextEntry = &Context->Cache;
984 
985  } else {
986 
987  //
988  // We have to seek in the entry buffer to the current entry within the buffer.
989  //
990 
991  CacheEntry = Add2Ptr( Context->Cache.Buffer, Context->Cache.CurrentOffset );
992  InjectEntry = Add2Ptr( Context->InjectionEntry.Buffer, Context->InjectionEntry.CurrentOffset );
993 
994  //
995  // Find names within the entries.
996  //
997 
998  CacheString.Buffer = NcGetFileName( CacheEntry, Offsets );
999  CacheString.Length = (USHORT) NcGetFileNameLength( CacheEntry, Offsets );
1000  CacheString.MaximumLength = CacheString.Length;
1001 
1002  InsertString.Buffer = NcGetFileName( InjectEntry, Offsets );
1003  InsertString.Length = (USHORT) NcGetFileNameLength( InjectEntry, Offsets );
1004  InsertString.MaximumLength = InsertString.Length;
1005 
1006  //
1007  // Compare the names
1008  //
1009 
1010  if (RtlCompareUnicodeString( &CacheString,
1011  &InsertString,
1012  IgnoreCase ) < 0) {
1013 
1014  //
1015  // Cache string comes first
1016  //
1017 
1018  NextEntry = &Context->Cache;
1019 
1020  } else {
1021 
1022  //
1023  // insert string comes first
1024  //
1025 
1026  NextEntry = &Context->InjectionEntry;
1027  }
1028  }
1029  return NextEntry;
1030 }
1031 
1032 _Success_(*Copied)
1033 ULONG
1035  _Out_ PVOID UserBuffer,
1036  _In_ ULONG UserOffset,
1037  _In_ ULONG UserSize,
1038  _Inout_ PNC_CACHE_ENTRY Entry,
1039  _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
1040  _Out_ PBOOLEAN Copied
1041  )
1042 /*++
1043 
1044 Routine Description:
1045 
1046  This routine copies a single enumeration result into the caller's
1047  buffer.
1048 
1049 Arguments:
1050 
1051  UserBuffer - Pointer to the caller's buffer.
1052 
1053  UserOffset - Offset within the caller's buffer that we intend to write new
1054  results.
1055 
1056  UserSize - Size of the caller's buffer, in bytes.
1057 
1058  Entry - Pointer to the directory entry that we intend to return.
1059 
1060  Offsets - Information describing the offsets for this enumeration class.
1061 
1062  Copied - Pointer to a boolean value indicating whether this routine copied
1063  a new entry or not.
1064 
1065 Return Value:
1066 
1067  The new offset in the user buffer that any future copies should use.
1068 
1069 --*/
1070 {
1071  PVOID Element = Add2Ptr( Entry->Buffer, Entry->CurrentOffset );
1072  PVOID Dest = Add2Ptr( UserBuffer, UserOffset );
1073  ULONG ElementSize = NcGetEntrySize( Element, Offsets );
1074  BOOLEAN LastElement = (BOOLEAN)(NcGetNextEntryOffset( Element, Offsets ) == 0);
1075 
1076  PAGED_CODE();
1077 
1078  if (UserSize - UserOffset >= ElementSize) {
1079 
1080  //
1081  // There is enough room for this element, so copy it.
1082  //
1083 
1084  RtlCopyMemory( Dest, Element, ElementSize );
1085  UserOffset += ElementSize;
1086  *Copied = TRUE;
1087 
1088  //
1089  // Update Entry's Offset
1090  //
1091 
1092  if (LastElement) {
1093 
1094  //
1095  // This was the last element in the entry, so we should clean the
1096  // entry.
1097  //
1098 
1099  ExFreePoolWithTag( Entry->Buffer, NC_TAG );
1100  Entry->Buffer = NULL;
1101  Entry->CurrentOffset = 0;
1102 
1103  //
1104  // The last element in cached entries have a NextEntryOffset of 0,
1105  // make sure that we report the actual next entry offset.
1106  //
1107 
1108  NcSetNextEntryOffset( Dest, Offsets, FALSE );
1109 
1110  } else {
1111 
1112  //
1113  // Entry has more elements, update offset counter.
1114  //
1115 
1116  Entry->CurrentOffset += ElementSize;
1117  }
1118 
1119  } else {
1120 
1121  //
1122  // User buffer does not have enough space.
1123  //
1124 
1125  *Copied = FALSE;
1126  }
1127 
1128  return UserOffset;
1129 }
1130 
1131 NTSTATUS
1133  _Out_ PNC_DIR_QRY_CONTEXT Context
1134  )
1135 /*++
1136 
1137 Routine Description:
1138 
1139  Initializes the stream handle context ready for directory enumeration
1140  requests.
1141 
1142 Arguments:
1143 
1144  Context - Pointer to the directory context.
1145 
1146 Return Value:
1147 
1148  The return value is the Status of the operation. Currently this operation
1149  cannot fail, so this function always returns STATUS_SUCCESS.
1150 
1151 --*/
1152 {
1153  NTSTATUS Status = STATUS_SUCCESS;
1154 
1155  PAGED_CODE();
1156 
1157  Context->EnumerationOutstanding = FALSE;
1158  Context->InUse = FALSE;
1159  Context->Cache.Buffer = NULL;
1160  Context->Cache.CurrentOffset = 0;
1161  Context->InjectionEntry.Buffer = NULL;
1162  Context->InjectionEntry.CurrentOffset = 0;
1163  Context->SearchString.Length = 0;
1164  Context->SearchString.MaximumLength = 0;
1165  Context->SearchString.Buffer = NULL;
1166 
1167  return Status;
1168 }
1169 
1170 
1171 NTSTATUS
1173  _Inout_ PNC_DIR_QRY_CONTEXT DirContext,
1174  _In_ PNC_INSTANCE_CONTEXT InstanceContext,
1175  _In_ PDIRECTORY_CONTROL_OFFSETS Offsets,
1176  _In_ PFLT_CALLBACK_DATA Data,
1177  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1178  _In_ NC_PATH_OVERLAP UserMappingOverlap,
1179  _Out_ PBOOLEAN FirstUsage
1180  )
1181 /*++
1182 
1183 Routine Description:
1184 
1185  Acquires the stream handle context and initializes it for a directory
1186  enumeration.
1187 
1188 Arguments:
1189 
1190  DirContext - Pointer to the directory context.
1191 
1192  InstanceContext - Pointer to this instance's context.
1193 
1194  Offsets - Offsets structure for this enumeration class.
1195 
1196  Data - Callback data for this operation.
1197 
1198  FltObjects - FltObjects structure for this operation.
1199 
1200  UserMappingOverlap - The overlap between the user mapping and this file
1201  object.
1202 
1203  FirstUsage - Weather or not this is the first usage of this handle in a
1204  directory enumeration.
1205 
1206 Return Value:
1207 
1208  The return value is the Status of the operation.
1209 
1210 --*/
1211 {
1212  NTSTATUS Status = STATUS_SUCCESS;
1213 
1214  PUNICODE_STRING SearchString = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName;
1215  FILE_INFORMATION_CLASS InformationClass = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass;
1216  BOOLEAN ResetSearch = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN );
1217  BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags,
1218  FO_OPENED_CASE_SENSITIVE );
1219 
1220  PAGED_CODE();
1221 
1222  //
1223  // This context could be in its first use. If it is, then we need to
1224  // setup the search string and information class.
1225  //
1226 
1227  if (DirContext->InUse == FALSE) {
1228 
1229  //
1230  // This was the first usage of the context.
1231  // We should set up the search string.
1232  //
1233 
1234  if (SearchString != NULL) {
1235 
1236  DirContext->SearchString.Buffer = ExAllocatePoolWithTag( PagedPool,
1237  SearchString->Length,
1239 
1240  if (DirContext->SearchString.Buffer == NULL) {
1241 
1242  Status = STATUS_INSUFFICIENT_RESOURCES;
1243  goto NcStreamHandleContextEnumSetupCleanup;
1244  }
1245 
1246  DirContext->SearchString.MaximumLength = SearchString->Length;
1247 
1248  if (IgnoreCase) {
1249 
1250  RtlUpcaseUnicodeString( &DirContext->SearchString, SearchString, FALSE );
1251 
1252  } else {
1253 
1254  RtlCopyUnicodeString( &DirContext->SearchString, SearchString );
1255  }
1256 
1257  DirContext->SearchString.Length = SearchString->Length;
1258 
1259  } else {
1260 
1261  RtlInitEmptyUnicodeString( &DirContext->SearchString,
1262  NULL,
1263  0 );
1264  }
1265 
1266  DirContext->InformationClass = InformationClass;
1267 
1268  //
1269  // We should write back to the caller so they know its the first usage.
1270  //
1271 
1272  *FirstUsage = TRUE;
1273 
1274  } else {
1275 
1276  //
1277  // This is not the fist usage, so write back to user.
1278  //
1279 
1280  *FirstUsage = FALSE;
1281 
1282  //
1283  // This is not the first query. Lets make sure that our data
1284  // is consistent. If the information classes don't line up
1285  // then our cache might be inconsistant. We should fail this
1286  // operation.
1287  //
1288  // TODO: Is this correct?
1289  //
1290 
1291  if (DirContext->InformationClass != InformationClass) {
1292 
1293  Status = STATUS_INVALID_PARAMETER;
1294  goto NcStreamHandleContextEnumSetupCleanup;
1295  }
1296  }
1297 
1298  if (!DirContext->InUse || ResetSearch) {
1299 
1300  //
1301  // Either this is the first use of the context,
1302  // or they are reseting the enumeration. We
1303  // should clear the cache either way.
1304  //
1305 
1306  if (DirContext->Cache.Buffer != NULL) {
1307 
1308  ExFreePoolWithTag( DirContext->Cache.Buffer, NC_TAG );
1309  DirContext->Cache.Buffer = NULL;
1310  DirContext->Cache.CurrentOffset = 0;
1311  }
1312 
1313  if (DirContext->InjectionEntry.Buffer != NULL) {
1314 
1315  ExFreePoolWithTag( DirContext->InjectionEntry.Buffer, NC_TAG );
1316  DirContext->InjectionEntry.Buffer = NULL;
1317  DirContext->InjectionEntry.CurrentOffset = 0;
1318  }
1319 
1320  //
1321  // Now that the cache is clear we can set up the injection entry.
1322  // The injection entry is the user mapping itself. Thus it only needs
1323  // to be injected if the directory being enumerated is the parent of
1324  // the user mapping.
1325  //
1326 
1327  if (UserMappingOverlap.Parent) {
1328 
1329  Status = NcEnumerateDirectorySetupInjection( DirContext,
1330  FltObjects,
1331  InstanceContext,
1332  Offsets,
1333  InformationClass );
1334  if (!NT_SUCCESS( Status )) {
1335 
1336  goto NcStreamHandleContextEnumSetupCleanup;
1337  }
1338  }
1339  }
1340 
1341  //
1342  // Now we know that the entry is setup.
1343  // Mark it as in use.
1344  //
1345 
1346  DirContext->InUse = TRUE;
1347  Status = STATUS_SUCCESS;
1348 
1349 NcStreamHandleContextEnumSetupCleanup:
1350 
1351  if (!NT_SUCCESS( Status )) {
1352 
1353  if (!DirContext->InUse) {
1354 
1355  //
1356  // We failed to set up the context for first use.
1357  // We should free our buffer we allocated.
1358  //
1359 
1360  if (DirContext->SearchString.Buffer != NULL) {
1361 
1362  ExFreePoolWithTag( DirContext->SearchString.Buffer, NC_TAG );
1363  DirContext->SearchString.Buffer = NULL;
1364  DirContext->SearchString.Length = 0;
1365  DirContext->SearchString.MaximumLength = 0;
1366  }
1367  }
1368  }
1369 
1370  return Status;
1371 }
1372 
1373 VOID
1375  _In_ PNC_DIR_QRY_CONTEXT DirContext
1376  )
1377 /*++
1378 
1379 Routine Description:
1380 
1381  Tears down any remaining state associated with a directory enumeration.
1382 
1383 Arguments:
1384 
1385  DirContext - Pointer to the directory context.
1386 
1387 Return Value:
1388 
1389  None.
1390 
1391 --*/
1392 {
1393  PAGED_CODE();
1394 
1395  if (DirContext->Cache.Buffer != NULL) {
1396 
1397  ExFreePoolWithTag( DirContext->Cache.Buffer,
1399 
1400  DirContext->Cache.Buffer = NULL;
1401  }
1402 
1403  if (DirContext->InjectionEntry.Buffer != NULL) {
1404 
1405  ExFreePoolWithTag( DirContext->InjectionEntry.Buffer,
1407 
1408  DirContext->InjectionEntry.Buffer = NULL;
1409  }
1410 
1411  if (DirContext->SearchString.Buffer != NULL) {
1412 
1413  ExFreePoolWithTag( DirContext->SearchString.Buffer,
1415 
1416  DirContext->SearchString.Buffer = NULL;
1417  }
1418 }
1419 
1420 
#define NC_DIR_QRY_SEARCH_STRING
Definition: nc.h:21
NTSTATUS NcStreamHandleContextAllocAndAttach(_In_ PFLT_FILTER Filter, _In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Out_ PNC_STREAM_HANDLE_CONTEXT *Context)
Definition: nccontext.c:126
NTSTATUS NcPopulateCacheEntry(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _In_ ULONG BufferLength, _In_ FILE_INFORMATION_CLASS FileInfoClass, _In_ PUNICODE_STRING SearchString, _In_ BOOLEAN RestartScan, _Out_ PNC_CACHE_ENTRY Cache)
Definition: ncdirenum.c:809
VOID NcSetNextEntryOffset(_Inout_ PVOID Buffer, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ BOOLEAN ForceLast)
Definition: ncoffsets.c:470
char * Buffer
Definition: nc.h:143
NC_MAPPING_ENTRY RealMapping
Definition: nc.h:186
NC_DIR_QRY_CONTEXT DirectoryQueryContext
Definition: nc.h:439
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
#define Add2Ptr(P, I)
Definition: minispy.h:238
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE Instance
Definition: nc.h:493
BOOLEAN NcSkipName(_In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ PNC_DIR_QRY_CONTEXT Context, _In_ NC_PATH_OVERLAP RealOverlap, _In_ PNC_MAPPING Mapping, _In_ BOOLEAN IgnoreCase)
Definition: ncdirenum.c:714
FLT_ASSERT(IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))
return TRUE
#define NcLockStreamHandleContext(C)
Definition: nc.h:444
BOOLEAN NcDetermineStructureOffsets(_Out_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ FILE_INFORMATION_CLASS Information)
Definition: ncoffsets.c:52
#define Max(a, b)
Definition: nc.h:38
NC_MAPPING Mapping
Definition: nc.h:233
NTSTATUS NcStreamHandleContextDirEnumCreate(_Out_ PNC_DIR_QRY_CONTEXT Context)
Definition: ncdirenum.c:1132
NC_MAPPING_ENTRY UserMapping
Definition: nc.h:187
_In_opt_ PFILE_OBJECT _In_opt_ PFLT_INSTANCE _In_ FLT_FILE_NAME_OPTIONS _Outptr_ PFLT_FILE_NAME_INFORMATION * FileNameInformation
Definition: nc.h:493
_In_ BOOLEAN _Out_ PFILE_BASIC_INFORMATION Buffer
#define NC_DIR_QRY_CACHE_TAG
Definition: nc.h:20
VOID NcSetFileName(_In_ PVOID Entry, _In_ PWSTR NewName, _In_ ULONG Length, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ BOOLEAN ForceLast)
Definition: ncoffsets.c:527
VOID NcStreamHandleContextEnumClose(_In_ PNC_DIR_QRY_CONTEXT DirContext)
Definition: ncdirenum.c:1374
NC_QUERY_DIRECTORY_FILE_TYPE NcQueryDirectoryFile
Definition: nccompat.c:79
PNC_CACHE_ENTRY NcDirEnumSelectNextEntry(_Inout_ PNC_DIR_QRY_CONTEXT Context, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ BOOLEAN IgnoreCase)
Definition: ncdirenum.c:920
ULONG NcGetNextEntryOffset(_In_ CONST PVOID Buffer, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets)
Definition: ncoffsets.c:240
UNREFERENCED_PARAMETER(FileObject)
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NTSTATUS NcEnumerateDirectorySetupInjection(_Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PNC_INSTANCE_CONTEXT InstanceContext, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ FILE_INFORMATION_CLASS InformationClass)
Definition: ncdirenum.c:463
ULONG NcGetEntrySize(_In_ CONST PVOID Buffer, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets)
Definition: ncoffsets.c:328
_Success_(IoStatus->Status==0) BOOLEAN CdoFastIoQueryBasicInfo(_In_ PFILE_OBJECT FileObject
BOOLEAN NcComparePath(_In_ PCUNICODE_STRING Name, _In_ PNC_MAPPING_ENTRY Mapping, _Out_opt_ PUNICODE_STRING Remainder, _In_ BOOLEAN IgnoreCase, _In_ BOOLEAN ContainsDevice, _Out_ PNC_PATH_OVERLAP Overlap)
Definition: ncpath.c:13
NTSTATUS NcStreamHandleContextEnumSetup(_Inout_ PNC_DIR_QRY_CONTEXT DirContext, _In_ PNC_INSTANCE_CONTEXT InstanceContext, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ NC_PATH_OVERLAP UserMappingOverlap, _Out_ PBOOLEAN FirstUsage)
Definition: ncdirenum.c:1172
VOID NcEnumerateDirectoryReset(_Inout_ PNC_DIR_QRY_CONTEXT DirCtx)
Definition: ncdirenum.c:682
PAGED_CODE()
_Success_ Copied ULONG NcCopyDirEnumEntry(_Out_ PVOID UserBuffer, _In_ ULONG UserOffset, _In_ ULONG UserSize, _Inout_ PNC_CACHE_ENTRY Entry, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _Out_ PBOOLEAN Copied)
Definition: ncdirenum.c:1034
IoStatus Status
PWSTR NcGetFileName(_In_ CONST PVOID Buffer, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets)
Definition: ncoffsets.c:368
LONG NcExceptionFilter(_In_ PEXCEPTION_POINTERS ExceptionPointer, _In_ BOOLEAN AccessingUserBuffer)
Definition: nchelper.c:322
NC_GLOBAL_DATA NcGlobalData
Definition: nc.c:335
#define NcUnlockStreamHandleContext(C)
Definition: nc.h:447
FLT_PREOP_CALLBACK_STATUS NcEnumerateDirectory(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
Definition: ncdirenum.c:39
BOOLEAN EnumerationOutstanding
Definition: nc.h:248
NTSTATUS NcCreateFileHelper(_In_ PFLT_FILTER Filter, _In_opt_ PFLT_INSTANCE Instance, _Out_ PHANDLE FileHandle, _Outptr_opt_ PFILE_OBJECT *FileObject, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _In_opt_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, _In_ ULONG EaLength, _In_ ULONG Flags, _In_opt_ PFILE_OBJECT ParentFileObject)
Definition: nchelper.c:195
NcLoadRegistryStringCleanup NC_TAG
Definition: ncinit.c:170
NC_CACHE_ENTRY Cache
Definition: nc.h:255
VOID NcSetShortName(_In_ PVOID Entry, _In_ PWSTR NewShortName, _In_ USHORT Length, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets)
Definition: ncoffsets.c:587
ULONG NcGetFileNameLength(_In_ CONST PVOID Buffer, _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets)
Definition: ncoffsets.c:299
int Parent
Definition: nc.h:218
PFLT_FILTER FilterHandle
Definition: nc.h:475
_In_opt_ PFILE_OBJECT FileObject
Definition: nc.h:493

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