ReactOS 0.4.15-dev-7918-g2a2556c
dirctrl.c
Go to the documentation of this file.
1/*++
2
3Copyright (c) 1989-2000 Microsoft Corporation
4
5Module Name:
6
7 DirCtrl.c
8
9Abstract:
10
11 This module implements the File Directory Control routines for Cdfs called
12 by the Fsd/Fsp dispatch drivers.
13
14
15--*/
16
17#include "cdprocs.h"
18
19//
20// The Bug check file id for this module
21//
22
23#define BugCheckFileId (CDFS_BUG_CHECK_DIRCTRL)
24
25//
26// Local support routines
27//
28
29_Requires_lock_held_(_Global_critical_region_)
31CdQueryDirectory (
32 _Inout_ PIRP_CONTEXT IrpContext,
37 );
38
39_Requires_lock_held_(_Global_critical_region_)
41CdNotifyChangeDirectory (
42 _Inout_ PIRP_CONTEXT IrpContext,
46 );
47
48VOID
50 _In_ PIRP_CONTEXT IrpContext,
55 _Out_ PBOOLEAN ReturnNextEntry,
57 _Out_ PBOOLEAN InitialQuery
58 );
59
62 _In_ PIRP_CONTEXT IrpContext,
65 _In_ BOOLEAN ReturnNextEntry
66 );
67
68#ifdef ALLOC_PRAGMA
69#pragma alloc_text(PAGE, CdCommonDirControl)
70#pragma alloc_text(PAGE, CdEnumerateIndex)
71#pragma alloc_text(PAGE, CdInitializeEnumeration)
72#pragma alloc_text(PAGE, CdNotifyChangeDirectory)
73#pragma alloc_text(PAGE, CdQueryDirectory)
74#endif
75
76
77
78_Requires_lock_held_(_Global_critical_region_)
80CdCommonDirControl (
81 _Inout_ PIRP_CONTEXT IrpContext,
83 )
84
85/*++
86
87Routine Description:
88
89 This routine is the entry point for the directory control operations. These
90 are directory enumerations and directory notify calls. We verify the
91 user's handle is for a directory and then call the appropriate routine.
92
93Arguments:
94
95 Irp - Irp for this request.
96
97Return Value:
98
99 NTSTATUS - Status returned from the lower level routines.
100
101--*/
102
103{
106
107 PFCB Fcb;
108 PCCB Ccb;
109
110 PAGED_CODE();
111
112 //
113 // Decode the user file object and fail this request if it is not
114 // a user directory.
115 //
116
117 if (CdDecodeFileObject( IrpContext,
119 &Fcb,
120 &Ccb ) != UserDirectoryOpen) {
121
124 }
125
126 //
127 // We know this is a directory control so we'll case on the
128 // minor function, and call a internal worker routine to complete
129 // the irp.
130 //
131
132 switch (IrpSp->MinorFunction) {
133
135
136 Status = CdQueryDirectory( IrpContext, Irp, IrpSp, Fcb, Ccb );
137 break;
138
140
141 Status = CdNotifyChangeDirectory( IrpContext, Irp, IrpSp, Ccb );
142 break;
143
144 default:
145
148 break;
149 }
150
151 return Status;
152}
153
154
155//
156// Local support routines
157//
158
159_Requires_lock_held_(_Global_critical_region_)
161CdQueryDirectory (
162 _Inout_ PIRP_CONTEXT IrpContext,
165 _In_ PFCB Fcb,
167 )
168
169/*++
170
171Routine Description:
172
173 This routine performs the query directory operation. It is responsible
174 for either completing of enqueuing the input Irp. We store the state of the
175 search in the Ccb.
176
177Arguments:
178
179 Irp - Supplies the Irp to process
180
181 IrpSp - Stack location for this Irp.
182
183 Fcb - Fcb for this directory.
184
185 Ccb - Ccb for this directory open.
186
187Return Value:
188
189 NTSTATUS - The return status for the operation
190
191--*/
192
193{
195 ULONG Information = 0;
196
197 ULONG LastEntry = 0;
198 ULONG NextEntry = 0;
199
200 ULONG FileNameBytes;
201 ULONG SeparatorBytes;
202 ULONG VersionStringBytes;
203
205 PDIRENT ThisDirent = NULL;
206 BOOLEAN InitialQuery;
207 BOOLEAN ReturnNextEntry = FALSE;
210 BOOLEAN DoCcbUpdate = FALSE;
211
212 PCHAR UserBuffer;
213 ULONG BytesRemainingInBuffer;
214
215 ULONG BaseLength;
216
218 PFILE_NAMES_INFORMATION NamesInfo;
219 PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
220 PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;
221
222 PAGED_CODE();
223
224 //
225 // Check if we support this search mode. Also remember the size of the base part of
226 // each of these structures.
227 //
228
229 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
230
232
234 FileName[0] );
235 break;
236
238
240 FileName[0] );
241 break;
242
244
246 FileName[0] );
247 break;
248
250
252 FileName[0] );
253 break;
254
256
258 FileName[0] );
259 break;
260
262
264 FileName[0] );
265 break;
266
267 default:
268
271 }
272
273 //
274 // Get the user buffer.
275 //
276
277 CdMapUserBuffer( IrpContext, &UserBuffer);
278
279 //
280 // Initialize our search context.
281 //
282
283 CdInitializeFileContext( IrpContext, &FileContext );
284
285 //
286 // Acquire the directory.
287 //
288
289 CdAcquireFileShared( IrpContext, Fcb );
290
291 //
292 // Use a try-finally to facilitate cleanup.
293 //
294
295 _SEH2_TRY {
296
297 //
298 // Verify the Fcb is still good.
299 //
300
301 CdVerifyFcbOperation( IrpContext, Fcb );
302
303 //
304 // Start by getting the initial state for the enumeration. This will set up the Ccb with
305 // the initial search parameters and let us know the starting offset in the directory
306 // to search.
307 //
308
309 CdInitializeEnumeration( IrpContext,
310 IrpSp,
311 Fcb,
312 Ccb,
314 &ReturnNextEntry,
316 &InitialQuery );
317
318 //
319 // The current dirent is stored in the InitialDirent field. We capture
320 // this here so that we have a valid restart point even if we don't
321 // find a single entry.
322 //
323
324 ThisDirent = &FileContext.InitialDirent->Dirent;
325
326 //
327 // At this point we are about to enter our query loop. We have
328 // determined the index into the directory file to begin the
329 // search. LastEntry and NextEntry are used to index into the user
330 // buffer. LastEntry is the last entry we've added, NextEntry is
331 // current one we're working on. If NextEntry is non-zero, then
332 // at least one entry was added.
333 //
334
335 while (TRUE) {
336
337 //
338 // If the user had requested only a single match and we have
339 // returned that, then we stop at this point. We update the Ccb with
340 // the status based on the last entry returned.
341 //
342
343 if ((NextEntry != 0) && ReturnSingleEntry) {
344
345 DoCcbUpdate = TRUE;
346 try_leave( Status );
347 }
348
349 //
350 // We try to locate the next matching dirent. Our search if based on a starting
351 // dirent offset, whether we should return the current or next entry, whether
352 // we should be doing a short name search and finally whether we should be
353 // checking for a version match.
354 //
355
356 Found = CdEnumerateIndex( IrpContext, Ccb, &FileContext, ReturnNextEntry );
357
358 //
359 // Initialize the value for the next search.
360 //
361
362 ReturnNextEntry = TRUE;
363
364 //
365 // If we didn't receive a dirent, then we are at the end of the
366 // directory. If we have returned any files, we exit with
367 // success, otherwise we return STATUS_NO_MORE_FILES.
368 //
369
370 if (!Found) {
371
372 if (NextEntry == 0) {
373
375
376 if (InitialQuery) {
377
379 }
380 }
381
382 DoCcbUpdate = TRUE;
383 try_leave( Status );
384 }
385
386 //
387 // Remember the dirent for the file we just found.
388 //
389
390 ThisDirent = &FileContext.InitialDirent->Dirent;
391
392 //
393 // Here are the rules concerning filling up the buffer:
394 //
395 // 1. The Io system garentees that there will always be
396 // enough room for at least one base record.
397 //
398 // 2. If the full first record (including file name) cannot
399 // fit, as much of the name as possible is copied and
400 // STATUS_BUFFER_OVERFLOW is returned.
401 //
402 // 3. If a subsequent record cannot completely fit into the
403 // buffer, none of it (as in 0 bytes) is copied, and
404 // STATUS_SUCCESS is returned. A subsequent query will
405 // pick up with this record.
406 //
407
408 //
409 // Let's compute the number of bytes we need to transfer the current entry.
410 //
411
412 SeparatorBytes =
413 VersionStringBytes = 0;
414
415 //
416 // We can look directly at the dirent that we found.
417 //
418
419 FileNameBytes = ThisDirent->CdFileName.FileName.Length;
420
421 //
422 // Compute the number of bytes for the version string if
423 // we will return this. Allow directories with illegal ";".
424 //
425
426 if (((Ccb->SearchExpression.VersionString.Length != 0) ||
427 (FlagOn(ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY))) &&
428 (ThisDirent->CdFileName.VersionString.Length != 0)) {
429
430 SeparatorBytes = 2;
431
432 VersionStringBytes = ThisDirent->CdFileName.VersionString.Length;
433 }
434
435 //
436 // If the slot for the next entry would be beyond the length of the
437 // user's buffer just exit (we know we've returned at least one entry
438 // already). This will happen when we align the pointer past the end.
439 //
440
441 if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) {
442
443 ReturnNextEntry = FALSE;
444 DoCcbUpdate = TRUE;
446 }
447
448 //
449 // Compute the number of bytes remaining in the buffer. Round this
450 // down to a WCHAR boundary so we can copy full characters.
451 //
452
453 BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry;
454 ClearFlag( BytesRemainingInBuffer, 1 );
455
456 //
457 // If this won't fit and we have returned a previous entry then just
458 // return STATUS_SUCCESS.
459 //
460
461 if ((BaseLength + FileNameBytes + SeparatorBytes + VersionStringBytes) > BytesRemainingInBuffer) {
462
463 //
464 // If we already found an entry then just exit.
465 //
466
467 if (NextEntry != 0) {
468
469 ReturnNextEntry = FALSE;
470 DoCcbUpdate = TRUE;
472 }
473
474 //
475 // Don't even try to return the version string if it doesn't all fit.
476 // Reduce the FileNameBytes to just fit in the buffer.
477 //
478
479 if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {
480
481 FileNameBytes = BytesRemainingInBuffer - BaseLength;
482 }
483
484 //
485 // Don't return any version string bytes.
486 //
487
488 VersionStringBytes =
489 SeparatorBytes = 0;
490
491 //
492 // Use a status code of STATUS_BUFFER_OVERFLOW. Also set
493 // ReturnSingleEntry so that we will exit the loop at the top.
494 //
495
498 }
499
500 //
501 // Protect access to the user buffer with an exception handler.
502 // Since (at our request) IO doesn't buffer these requests, we have
503 // to guard against a user messing with the page protection and other
504 // such trickery.
505 //
506
507 _SEH2_TRY {
508
509 //
510 // Zero and initialize the base part of the current entry.
511 //
512
513 RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
514 BaseLength );
515
516 //
517 // Now we have an entry to return to our caller.
518 // We'll case on the type of information requested and fill up
519 // the user buffer if everything fits.
520 //
521
522 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
523
529
530 DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
531
532 //
533 // Use the create time for all the time stamps.
534 //
535
536 CdConvertCdTimeToNtTime( IrpContext,
537 FileContext.InitialDirent->Dirent.CdTime,
538 &DirInfo->CreationTime );
539
540 DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime;
541
542 //
543 // Set the attributes and sizes separately for directories and
544 // files.
545 //
546
547 if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
548
549 DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
550
552
553 } else {
554
555 DirInfo->EndOfFile.QuadPart = FileContext.FileSize;
556 DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize );
557
559 }
560
561 if (FlagOn( ThisDirent->DirentFlags,
563
565 }
566
567 DirInfo->FileIndex = ThisDirent->DirentOffset;
568
569 DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
570
571 break;
572
574
575 NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
576
577 NamesInfo->FileIndex = ThisDirent->DirentOffset;
578
579 NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
580
581 break;
582
583 /* ReactOS Change: GCC "enumeration value not handled in switch" */
584 default: break;
585 }
586
587 //
588 // Fill in the FileId
589 //
590
591 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
592
594
595 IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION );
596 CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent );
597 break;
598
600
601 IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION );
602 CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent );
603 break;
604
605 default:
606 break;
607 }
608
609 //
610 // Now copy as much of the name as possible. We also may have a version
611 // string to copy.
612 //
613
614 if (FileNameBytes != 0) {
615
616 //
617 // This is a Unicode name, we can copy the bytes directly.
618 //
619
620 RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
621 ThisDirent->CdFileName.FileName.Buffer,
622 FileNameBytes );
623
624 if (SeparatorBytes != 0) {
625
626 *(Add2Ptr( UserBuffer,
627 NextEntry + BaseLength + FileNameBytes,
628 PWCHAR )) = L';';
629
630 if (VersionStringBytes != 0) {
631
632 RtlCopyMemory( Add2Ptr( UserBuffer,
633 NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ),
634 PVOID ),
635 ThisDirent->CdFileName.VersionString.Buffer,
636 VersionStringBytes );
637 }
638 }
639 }
640
641 //
642 // Fill in the short name if we got STATUS_SUCCESS. The short name
643 // may already be in the file context. Otherwise we will check
644 // whether the long name is 8.3. Special case the self and parent
645 // directory names.
646 //
647
648 if ((Status == STATUS_SUCCESS) &&
651 (Ccb->SearchExpression.VersionString.Length == 0) &&
652 !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
653
654 //
655 // If we already have the short name then copy into the user's buffer.
656 //
657
658 if (FileContext.ShortName.FileName.Length != 0) {
659
660 RtlCopyMemory( DirInfo->ShortName,
661 FileContext.ShortName.FileName.Buffer,
662 FileContext.ShortName.FileName.Length );
663
664 DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
665
666 //
667 // If the short name length is currently zero then check if
668 // the long name is not 8.3. We can copy the short name in
669 // unicode form directly into the caller's buffer.
670 //
671
672 } else {
673
674 if (!CdIs8dot3Name( IrpContext,
675 ThisDirent->CdFileName.FileName )) {
676
677 CdGenerate8dot3Name( IrpContext,
678 &ThisDirent->CdCaseFileName.FileName,
679 ThisDirent->DirentOffset,
680 DirInfo->ShortName,
681 &FileContext.ShortName.FileName.Length );
682
683 DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
684 }
685 }
686
687 }
688
689 //
690 // Sum the total number of bytes for the information field.
691 //
692
693 FileNameBytes += SeparatorBytes + VersionStringBytes;
694
695 //
696 // Update the information with the number of bytes stored in the
697 // buffer. We quad-align the existing buffer to add any necessary
698 // pad bytes.
699 //
700
701 Information = NextEntry + BaseLength + FileNameBytes;
702
703 //
704 // Go back to the previous entry and fill in the update to this entry.
705 //
706
707 *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;
708
709 //
710 // Set up our variables for the next dirent.
711 //
712
713 InitialQuery = FALSE;
714
715 LastEntry = NextEntry;
716 NextEntry = QuadAlign( Information );
717
718#ifdef _MSC_VER
719#pragma warning(suppress: 6320)
720#endif
722
723 //
724 // We had a problem filling in the user's buffer, so stop and
725 // fail this request. This is the only reason any exception
726 // would have occured at this level.
727 //
728
729 Information = 0;
731 } _SEH2_END;
732 }
733
734 DoCcbUpdate = TRUE;
735
736 } _SEH2_FINALLY {
737
738 //
739 // Cleanup our search context - *before* aquiring the FCB mutex exclusive,
740 // else can block on threads in cdcreateinternalstream/purge which
741 // hold the FCB but are waiting for all maps in this stream to be released.
742 //
743
744 CdCleanupFileContext( IrpContext, &FileContext );
745
746 //
747 // Now we can safely aqure the FCB mutex if we need to.
748 //
749
750 if (DoCcbUpdate && !NT_ERROR( Status )) {
751
752 //
753 // Update the Ccb to show the current state of the enumeration.
754 //
755
756 CdLockFcb( IrpContext, Fcb );
757
758 Ccb->CurrentDirentOffset = ThisDirent->DirentOffset;
759
761
762 if (ReturnNextEntry) {
763
765 }
766
767 CdUnlockFcb( IrpContext, Fcb );
768 }
769
770 //
771 // Release the Fcb.
772 //
773
774 CdReleaseFile( IrpContext, Fcb );
775 } _SEH2_END;
776
777 //
778 // Complete the request here.
779 //
780
781 Irp->IoStatus.Information = Information;
782
783 CdCompleteRequest( IrpContext, Irp, Status );
784 return Status;
785}
786
787
788//
789// Local support routines
790//
791
792_Requires_lock_held_(_Global_critical_region_)
794CdNotifyChangeDirectory (
795 _Inout_ PIRP_CONTEXT IrpContext,
799 )
800
801/*++
802
803Routine Description:
804
805 This routine performs the notify change directory operation. It is
806 responsible for either completing of enqueuing the input Irp. Although there
807 will never be a notify signalled on a CDROM disk we still support this call.
808
809 We have already checked that this is not an OpenById handle.
810
811Arguments:
812
813 Irp - Supplies the Irp to process
814
815 IrpSp - Io stack location for this request.
816
817 Ccb - Handle to the directory being watched.
818
819Return Value:
820
821 NTSTATUS - STATUS_PENDING, any other error will raise.
822
823--*/
824
825{
826 PAGED_CODE();
827
828 //
829 // Always set the wait bit in the IrpContext so the initial wait can't fail.
830 //
831
832 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
833
834 //
835 // Acquire the Vcb shared.
836 //
837
838 CdAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );
839
840 //
841 // Use a try-finally to facilitate cleanup.
842 //
843
844 _SEH2_TRY {
845
846 //
847 // Verify the Vcb.
848 //
849
850 CdVerifyVcb( IrpContext, IrpContext->Vcb );
851
852 //
853 // Call the Fsrtl package to process the request. We cast the
854 // unicode strings to ansi strings as the dir notify package
855 // only deals with memory matching.
856 //
857
858 FsRtlNotifyFullChangeDirectory( IrpContext->Vcb->NotifySync,
859 &IrpContext->Vcb->DirNotifyList,
860 Ccb,
861 (PSTRING) &IrpSp->FileObject->FileName,
863 FALSE,
864 IrpSp->Parameters.NotifyDirectory.CompletionFilter,
865 Irp,
866 NULL,
867 NULL );
868
869 } _SEH2_FINALLY {
870
871 //
872 // Release the Vcb.
873 //
874
875 CdReleaseVcb( IrpContext, IrpContext->Vcb );
876 } _SEH2_END;
877
878 //
879 // Cleanup the IrpContext.
880 //
881
882 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
883
884 return STATUS_PENDING;
885}
886
887
888//
889// Local support routine
890//
891
892VOID
894 _In_ PIRP_CONTEXT IrpContext,
896 _In_ PFCB Fcb,
899 _Out_ PBOOLEAN ReturnNextEntry,
901 _Out_ PBOOLEAN InitialQuery
902 )
903
904/*++
905
906Routine Description:
907
908 This routine is called to initialize the enumeration variables and structures.
909 We look at the state of a previous enumeration from the Ccb as well as any
910 input values from the user. On exit we will position the FileContext at
911 a file in the directory and let the caller know whether this entry or the
912 next entry should be returned.
913
914Arguments:
915
916 IrpSp - Irp stack location for this request.
917
918 Fcb - Fcb for this directory.
919
920 Ccb - Ccb for the directory handle.
921
922 FileContext - FileContext to use for this enumeration.
923
924 ReturnNextEntry - Address to store whether we should return the entry at
925 the FileContext position or the next entry.
926
927 ReturnSingleEntry - Address to store whether we should only return
928 a single entry.
929
930 InitialQuery - Address to store whether this is the first enumeration
931 query on this handle.
932
933Return Value:
934
935 None.
936
937--*/
938
939{
941
943 CD_NAME WildCardName;
944 CD_NAME SearchExpression;
945
946 ULONG CcbFlags;
947
949 ULONG LastDirentOffset;
950 BOOLEAN KnownOffset;
951
953
954 PAGED_CODE();
955
956 //
957 // If the user has specified that the scan be restarted, and has specicified
958 // a new query pattern, reinitialize the CCB.
959 //
960
962
963 CdLockFcb( IrpContext, Fcb );
964
966 if (FileName && FileName->Length > 0) {
967
969
970 CdFreePool( &Ccb->SearchExpression.FileName.Buffer );
971 }
972
976 }
977
978 CdUnlockFcb( IrpContext, Fcb );
979 }
980
981 //
982 // If this is the initial query then build a search expression from the input
983 // file name.
984 //
985
987
989
990 CcbFlags = 0;
991
992 //
993 // If the filename is not specified or is a single '*' then we will
994 // match all names.
995 //
996
997 if ((FileName == NULL) ||
998 (FileName->Buffer == NULL) ||
999 (FileName->Length == 0) ||
1000 ((FileName->Length == sizeof( WCHAR )) &&
1001 (FileName->Buffer[0] == L'*'))) {
1002
1003 SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL );
1004 RtlZeroMemory( &SearchExpression, sizeof( SearchExpression ));
1005
1006 //
1007 // Otherwise build the CdName from the name in the stack location.
1008 // This involves building both the name and version portions and
1009 // checking for wild card characters. We also upcase the string if
1010 // this is a case-insensitive search.
1011 //
1012
1013 } else {
1014
1015 //
1016 // Create a CdName to check for wild cards.
1017 //
1018
1019 WildCardName.FileName = *FileName;
1020
1021 CdConvertNameToCdName( IrpContext, &WildCardName );
1022
1023 //
1024 // The name better have at least one character.
1025 //
1026
1027 if (WildCardName.FileName.Length == 0) {
1028
1030 }
1031
1032 //
1033 // Check for wildcards in the separate components.
1034 //
1035
1036 if (FsRtlDoesNameContainWildCards( &WildCardName.FileName)) {
1037
1039 }
1040
1041 if ((WildCardName.VersionString.Length != 0) &&
1042 (FsRtlDoesNameContainWildCards( &WildCardName.VersionString ))) {
1043
1045
1046 //
1047 // Check if this is a wild card only and match all version
1048 // strings.
1049 //
1050
1051 if ((WildCardName.VersionString.Length == sizeof( WCHAR )) &&
1052 (WildCardName.VersionString.Buffer[0] == L'*')) {
1053
1055 }
1056 }
1057
1058 //
1059 // Now create the search expression to store in the Ccb.
1060 //
1061
1063 FileName->Length,
1065
1066 SearchExpression.FileName.MaximumLength = FileName->Length;
1067
1068 //
1069 // Either copy the name directly or perform the upcase.
1070 //
1071
1073
1075 FileName,
1076 FALSE );
1077
1078 //
1079 // This should never fail.
1080 //
1083
1084 } else {
1085
1086 RtlCopyMemory( SearchExpression.FileName.Buffer,
1087 FileName->Buffer,
1088 FileName->Length );
1089 }
1090
1091 //
1092 // Now split into the separate name and version components.
1093 //
1094
1095 SearchExpression.FileName.Length = WildCardName.FileName.Length;
1096 SearchExpression.VersionString.Length = WildCardName.VersionString.Length;
1097 SearchExpression.VersionString.MaximumLength = WildCardName.VersionString.MaximumLength;
1098
1099 SearchExpression.VersionString.Buffer = Add2Ptr( SearchExpression.FileName.Buffer,
1100 SearchExpression.FileName.Length + sizeof( WCHAR ),
1101 PWCHAR );
1102 }
1103
1104 //
1105 // But we do not want to return the constant "." and ".." entries for
1106 // the root directory, for consistency with the rest of Microsoft's
1107 // filesystems.
1108 //
1109
1110 if (Fcb == Fcb->Vcb->RootIndexFcb) {
1111
1113 }
1114
1115 //
1116 // Now lock the Fcb in order to update the Ccb with the inital
1117 // enumeration values.
1118 //
1119
1120 CdLockFcb( IrpContext, Fcb );
1121
1122 //
1123 // Check again that this is the initial search.
1124 //
1125
1127
1128 //
1129 // Update the values in the Ccb.
1130 //
1131
1132 Ccb->CurrentDirentOffset = Fcb->StreamOffset;
1133 Ccb->SearchExpression = SearchExpression;
1134
1135 //
1136 // Set the appropriate flags in the Ccb.
1137 //
1138
1140
1141 //
1142 // Otherwise cleanup any buffer allocated here.
1143 //
1144
1145 } else {
1146
1147 if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {
1148
1149 CdFreePool( &SearchExpression.FileName.Buffer );
1150 }
1151 }
1152
1153 //
1154 // Otherwise lock the Fcb so we can read the current enumeration values.
1155 //
1156
1157 } else {
1158
1159 CdLockFcb( IrpContext, Fcb );
1160 }
1161
1162 //
1163 // Capture the current state of the enumeration.
1164 //
1165 // If the user specified an index then use his offset. We always
1166 // return the next entry in this case.
1167 //
1168
1170
1171 KnownOffset = FALSE;
1173 *ReturnNextEntry = TRUE;
1174
1175 //
1176 // If we are restarting the scan then go from the self entry.
1177 //
1178
1179 } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {
1180
1181 KnownOffset = TRUE;
1182 DirentOffset = Fcb->StreamOffset;
1183 *ReturnNextEntry = FALSE;
1184
1185 //
1186 // Otherwise use the values from the Ccb.
1187 //
1188
1189 } else {
1190
1191 KnownOffset = TRUE;
1192 DirentOffset = Ccb->CurrentDirentOffset;
1193 *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
1194 }
1195
1196 //
1197 // Unlock the Fcb.
1198 //
1199
1200 CdUnlockFcb( IrpContext, Fcb );
1201
1202 //
1203 // We have the starting offset in the directory and whether to return
1204 // that entry or the next. If we are at the beginning of the directory
1205 // and are returning that entry, then tell our caller this is the
1206 // initial query.
1207 //
1208
1209 *InitialQuery = FALSE;
1210
1211 if ((DirentOffset == Fcb->StreamOffset) &&
1212 !(*ReturnNextEntry)) {
1213
1214 *InitialQuery = TRUE;
1215 }
1216
1217 //
1218 // If there is no file object then create it now.
1219 //
1220
1221 CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);
1222
1223 //
1224 // Determine the offset in the stream to position the FileContext and
1225 // whether this offset is known to be a file offset.
1226 //
1227 // If this offset is known to be safe then go ahead and position the
1228 // file context. This handles the cases where the offset is the beginning
1229 // of the stream, the offset is from a previous search or this is the
1230 // initial query.
1231 //
1232
1233 if (KnownOffset) {
1234
1236
1237 //
1238 // Otherwise we walk through the directory from the beginning until
1239 // we reach the entry which contains this offset.
1240 //
1241
1242 } else {
1243
1244 LastDirentOffset = Fcb->StreamOffset;
1245 Found = TRUE;
1246
1247 CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
1248
1249 //
1250 // If the requested offset is prior to the beginning offset in the stream
1251 // then don't return the next entry.
1252 //
1253
1254 if (DirentOffset < LastDirentOffset) {
1255
1256 *ReturnNextEntry = FALSE;
1257
1258 //
1259 // Else look for the last entry which ends past the desired index.
1260 //
1261
1262 } else {
1263
1264 //
1265 // Keep walking through the directory until we run out of
1266 // entries or we find an entry which ends beyond the input
1267 // index value.
1268 //
1269
1270 do {
1271
1272 //
1273 // If we have passed the index value then exit.
1274 //
1275
1276 if (FileContext->InitialDirent->Dirent.DirentOffset > DirentOffset) {
1277
1278 Found = FALSE;
1279 break;
1280 }
1281
1282 //
1283 // Remember the current position in case we need to go back.
1284 //
1285
1286 LastDirentOffset = FileContext->InitialDirent->Dirent.DirentOffset;
1287
1288 //
1289 // Exit if the next entry is beyond the desired index value.
1290 //
1291
1292 if (LastDirentOffset + FileContext->InitialDirent->Dirent.DirentLength > DirentOffset) {
1293
1294 break;
1295 }
1296
1298
1299 } while (Found);
1300
1301 //
1302 // If we didn't find the entry then go back to the last known entry.
1303 // This can happen if the index lies in the unused range at the
1304 // end of a sector.
1305 //
1306
1307 if (!Found) {
1308
1309 CdCleanupFileContext( IrpContext, FileContext );
1310 CdInitializeFileContext( IrpContext, FileContext );
1311
1312 CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
1313 }
1314 }
1315 }
1316
1317 //
1318 // Only update the dirent name if we will need it for some reason.
1319 // Don't update this name if we are returning the next entry and
1320 // the search string has a version component.
1321 //
1322
1323 FileContext->ShortName.FileName.Length = 0;
1324
1325 if (!(*ReturnNextEntry) ||
1326 (Ccb->SearchExpression.VersionString.Length == 0)) {
1327
1328 //
1329 // Update the name in the dirent into filename and version components.
1330 //
1331
1332 CdUpdateDirentName( IrpContext,
1333 &FileContext->InitialDirent->Dirent,
1335 }
1336
1337 //
1338 // Look at the flag in the IrpSp indicating whether to return just
1339 // one entry.
1340 //
1341
1343
1345
1347 }
1348
1349 return;
1350}
1351
1352
1353//
1354// Local support routine
1355//
1356
1357BOOLEAN
1359 _In_ PIRP_CONTEXT IrpContext,
1360 _In_ PCCB Ccb,
1362 _In_ BOOLEAN ReturnNextEntry
1363 )
1364
1365/*++
1366
1367Routine Description:
1368
1369 This routine is the worker routine for index enumeration. We are positioned
1370 at some dirent in the directory and will either return the first match
1371 at that point or look to the next entry. The Ccb contains details about
1372 the type of matching to do. If the user didn't specify a version in
1373 his search string then we only return the first version of a sequence
1374 of files with versions. We also don't return any associated files.
1375
1376Arguments:
1377
1378 Ccb - Ccb for this directory handle.
1379
1380 FileContext - File context already positioned at some entry in the directory.
1381
1382 ReturnNextEntry - Indicates if we are returning this entry or should start
1383 with the next entry.
1384
1385Return Value:
1386
1387 BOOLEAN - TRUE if next entry is found, FALSE otherwise.
1388
1389--*/
1390
1391{
1392 PDIRENT PreviousDirent = NULL;
1393 PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
1394
1396
1397 PAGED_CODE();
1398
1399 //
1400 // Loop until we find a match or exaust the directory.
1401 //
1402
1403 while (TRUE) {
1404
1405 //
1406 // Move to the next entry unless we want to consider the current
1407 // entry.
1408 //
1409
1410 if (ReturnNextEntry) {
1411
1412 if (!CdLookupNextInitialFileDirent( IrpContext, Ccb->Fcb, FileContext )) {
1413
1414 break;
1415 }
1416
1417 PreviousDirent = ThisDirent;
1418 ThisDirent = &FileContext->InitialDirent->Dirent;
1419
1420 CdUpdateDirentName( IrpContext, ThisDirent, FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
1421
1422 } else {
1423
1424 ReturnNextEntry = TRUE;
1425 }
1426
1427 //
1428 // Don't bother if we have a constant entry and are ignoring them.
1429 //
1430
1431 if (FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
1433
1434 continue;
1435 }
1436
1437 //
1438 // Look at the current entry if it is not an associated file
1439 // and the name doesn't match the previous file if the version
1440 // name is not part of the search.
1441 //
1442
1443 if (!FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_ASSOC )) {
1444
1445 //
1446 // Check if this entry matches the previous entry except
1447 // for version number and whether we should return the
1448 // entry in that case. Go directly to the name comparison
1449 // if:
1450 //
1451 // There is no previous entry.
1452 // The search expression has a version component.
1453 // The name length doesn't match the length of the previous entry.
1454 // The base name strings don't match.
1455 //
1456
1457 if ((PreviousDirent == NULL) ||
1458 (Ccb->SearchExpression.VersionString.Length != 0) ||
1459 (PreviousDirent->CdCaseFileName.FileName.Length != ThisDirent->CdCaseFileName.FileName.Length) ||
1460 FlagOn( PreviousDirent->DirentFlags, CD_ATTRIBUTE_ASSOC ) ||
1461 !RtlEqualMemory( PreviousDirent->CdCaseFileName.FileName.Buffer,
1462 ThisDirent->CdCaseFileName.FileName.Buffer,
1463 ThisDirent->CdCaseFileName.FileName.Length )) {
1464
1465 //
1466 // If we match all names then return to our caller.
1467 //
1468
1470
1471 FileContext->ShortName.FileName.Length = 0;
1472 Found = TRUE;
1473 break;
1474 }
1475
1476 //
1477 // Check if the long name matches the search expression.
1478 //
1479
1480 if (CdIsNameInExpression( IrpContext,
1481 &ThisDirent->CdCaseFileName,
1482 &Ccb->SearchExpression,
1483 Ccb->Flags,
1484 TRUE )) {
1485
1486 //
1487 // Let our caller know we found an entry.
1488 //
1489
1490 Found = TRUE;
1491 FileContext->ShortName.FileName.Length = 0;
1492 break;
1493 }
1494
1495 //
1496 // The long name didn't match so we need to check for a
1497 // possible short name match. There is no match if the
1498 // long name is 8dot3 or the search expression has a
1499 // version component. Special case the self and parent
1500 // entries.
1501 //
1502
1503 if ((Ccb->SearchExpression.VersionString.Length == 0) &&
1504 !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
1505 !CdIs8dot3Name( IrpContext,
1506 ThisDirent->CdFileName.FileName )) {
1507
1508 CdGenerate8dot3Name( IrpContext,
1509 &ThisDirent->CdCaseFileName.FileName,
1510 ThisDirent->DirentOffset,
1511 FileContext->ShortName.FileName.Buffer,
1512 &FileContext->ShortName.FileName.Length );
1513
1514 //
1515 // Check if this name matches.
1516 //
1517
1518 if (CdIsNameInExpression( IrpContext,
1520 &Ccb->SearchExpression,
1521 Ccb->Flags,
1522 FALSE )) {
1523
1524 //
1525 // Let our caller know we found an entry.
1526 //
1527
1528 Found = TRUE;
1529 break;
1530 }
1531 }
1532 }
1533 }
1534 }
1535
1536 //
1537 // If we found the entry then make sure we walk through all of the
1538 // file dirents.
1539 //
1540
1541 if (Found) {
1542
1543 CdLookupLastFileDirent( IrpContext, Ccb->Fcb, FileContext );
1544 }
1545
1546 return Found;
1547}
1548
1549
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define PAGED_CODE()
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define CD_ATTRIBUTE_DIRECTORY
Definition: cd.h:354
#define CD_ATTRIBUTE_ASSOC
Definition: cd.h:355
#define CD_ATTRIBUTE_HIDDEN
Definition: cd.h:353
#define CdConvertCdTimeToNtTime(IC, CD, NT)
Definition: cd.h:394
VOID CdCompleteRequest(_Inout_opt_ PIRP_CONTEXT IrpContext, _Inout_opt_ PIRP Irp, _In_ NTSTATUS Status)
Definition: cddata.c:914
VOID CdInitializeEnumeration(_In_ PIRP_CONTEXT IrpContext, _In_ PIO_STACK_LOCATION IrpSp, _In_ PFCB Fcb, _Inout_ PCCB Ccb, _Inout_ PFILE_ENUM_CONTEXT FileContext, _Out_ PBOOLEAN ReturnNextEntry, _Out_ PBOOLEAN ReturnSingleEntry, _Out_ PBOOLEAN InitialQuery)
Definition: dirctrl.c:893
BOOLEAN CdEnumerateIndex(_In_ PIRP_CONTEXT IrpContext, _In_ PCCB Ccb, _Inout_ PFILE_ENUM_CONTEXT FileContext, _In_ BOOLEAN ReturnNextEntry)
Definition: dirctrl.c:1358
Dirent DirentOffset
Definition: dirsup.c:444
return Found
Definition: dirsup.c:1270
static INLINE VOID CdVerifyOrCreateDirStreamFile(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb)
Definition: cdprocs.h:242
#define LlSectorAlign(L)
Definition: cdprocs.h:1584
#define CdLockFcb(IC, F)
Definition: cdprocs.h:1044
#define CdMapUserBuffer(IC, UB)
Definition: cdprocs.h:383
#define CdReleaseFile(IC, F)
Definition: cdprocs.h:1003
#define CdReleaseVcb(IC, V)
Definition: cdprocs.h:985
VOID CdVerifyVcb(_In_ PIRP_CONTEXT IrpContext, _Inout_ PVCB Vcb)
Definition: verfysup.c:411
VOID CdLookupLastFileDirent(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb, _In_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1426
@ UserDirectoryOpen
Definition: cdprocs.h:576
VOID CdUpdateDirentName(_In_ PIRP_CONTEXT IrpContext, _Inout_ PDIRENT Dirent, _In_ ULONG IgnoreCase)
Definition: dirsup.c:534
#define CdInitializeFileContext(IC, FC)
Definition: cdprocs.h:527
_In_ PFCB _In_ PCD_NAME _In_ BOOLEAN _Inout_ PFILE_ENUM_CONTEXT FileContext
Definition: cdprocs.h:442
#define QuadAlign(Ptr)
Definition: cdprocs.h:1572
BOOLEAN CdIsNameInExpression(_In_ PIRP_CONTEXT IrpContext, _In_ PCD_NAME CurrentName, _In_ PCD_NAME SearchExpression, _In_ ULONG WildcardFlags, _In_ BOOLEAN CheckVersion)
Definition: namesup.c:844
#define CdAcquireVcbShared(IC, V, I)
Definition: cdprocs.h:982
#define TAG_ENUM_EXPRESSION
Definition: cdprocs.h:88
_In_ PFCB Fcb
Definition: cdprocs.h:159
#define CdLookupInitialFileDirent(IC, F, FC, DO)
Definition: cdprocs.h:551
VOID CdGenerate8dot3Name(_In_ PIRP_CONTEXT IrpContext, _In_ PUNICODE_STRING FileName, _In_ ULONG DirentOffset, _Out_writes_bytes_to_(BYTE_COUNT_8_DOT_3, *ShortByteCount) PWCHAR ShortFileName, _Out_ PUSHORT ShortByteCount)
Definition: namesup.c:550
BOOLEAN CdLookupNextInitialFileDirent(_In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb, _Inout_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1275
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:592
#define try_leave(S)
Definition: cdprocs.h:2180
BOOLEAN CdVerifyFcbOperation(_In_opt_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb)
Definition: verfysup.c:615
#define CdAcquireFileShared(IC, F)
Definition: cdprocs.h:997
#define CdFreePool(x)
Definition: cdprocs.h:2190
#define CdPagedPool
Definition: cdprocs.h:1380
VOID CdCleanupFileContext(_In_ PIRP_CONTEXT IrpContext, _In_ PFILE_ENUM_CONTEXT FileContext)
Definition: dirsup.c:1636
BOOLEAN CdIs8dot3Name(_In_ PIRP_CONTEXT IrpContext, _In_ UNICODE_STRING FileName)
Definition: namesup.c:429
#define CdUnlockFcb(IC, F)
Definition: cdprocs.h:1060
#define CdRaiseStatus(IC, S)
Definition: cdprocs.h:1859
#define CCB_FLAG_IGNORE_CASE
Definition: cdstruc.h:1105
#define DIRENT_FLAG_CONSTANT_ENTRY
Definition: cdstruc.h:1671
#define CCB_FLAG_ENUM_MATCH_ALL
Definition: cdstruc.h:1116
#define CCB_FLAG_ENUM_RETURN_NEXT
Definition: cdstruc.h:1118
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1215
#define CCB_FLAG_ENUM_NAME_EXP_HAS_WILD
Definition: cdstruc.h:1114
#define CdSetFidFromParentAndDirent(I, F, D)
Definition: cdstruc.h:1838
#define CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY
Definition: cdstruc.h:1120
#define CCB_FLAG_ENUM_INITIALIZED
Definition: cdstruc.h:1119
#define CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD
Definition: cdstruc.h:1115
#define CCB_FLAG_ENUM_VERSION_MATCH_ALL
Definition: cdstruc.h:1117
#define _Requires_lock_held_(lock)
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define ClearFlag(_F, _SF)
Definition: ext2fs.h:191
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
struct _FileName FileName
Definition: fatprocs.h:896
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_ BOOLEAN ReturnSingleEntry
Definition: fltkernel.h:2295
@ FileDirectoryInformation
Definition: from_kernel.h:62
@ FileIdBothDirectoryInformation
Definition: from_kernel.h:98
@ FileNamesInformation
Definition: from_kernel.h:73
@ FileFullDirectoryInformation
Definition: from_kernel.h:63
@ FileBothDirectoryInformation
Definition: from_kernel.h:64
@ FileIdFullDirectoryInformation
Definition: from_kernel.h:99
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define Add2Ptr(PTR, INC)
#define RtlEqualMemory(a, b, c)
Definition: kdvm.h:18
if(dx< 0)
Definition: linetemp.h:194
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
BOOLEAN NTAPI FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)
Definition: name.c:464
VOID NTAPI FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
Definition: notify.c:1487
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_INVALID_INFO_CLASS
Definition: ntstatus.h:240
#define L(x)
Definition: ntvdm.h:50
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define IRP_MN_QUERY_DIRECTORY
Definition: rdpdr.c:55
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY
Definition: rdpdr.c:56
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
#define __analysis_assert(e)
Definition: specstrings.h:259
Definition: cdstruc.h:1067
UNICODE_STRING VersionString
Definition: cdstruc.h:250
UNICODE_STRING FileName
Definition: cdstruc.h:244
UCHAR DirentFlags
Definition: cdstruc.h:1613
CD_NAME CdFileName
Definition: cdstruc.h:1656
UCHAR Flags
Definition: cdstruc.h:1619
ULONG DirentOffset
Definition: cdstruc.h:1585
CD_NAME CdCaseFileName
Definition: cdstruc.h:1657
Definition: cdstruc.h:902
ULONG Flags
Definition: ntfs.h:536
PVCB Vcb
Definition: cdstruc.h:933
struct _FCB::@720::@723 Fcb
FILE_NAME_NODE ShortName
Definition: fatstruc.h:1115
LARGE_INTEGER CreationTime
Definition: from_kernel.h:141
LARGE_INTEGER AllocationSize
Definition: from_kernel.h:146
LARGE_INTEGER LastWriteTime
Definition: from_kernel.h:143
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
union _IO_STACK_LOCATION::@1564 Parameters
struct _IO_STACK_LOCATION::@3978::@3985 NotifyDirectory
struct _IO_STACK_LOCATION::@3978::@3984 QueryDirectory
USHORT MaximumLength
Definition: env_spec_w32.h:370
struct _FCB * RootIndexFcb
Definition: cdstruc.h:560
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
char CCHAR
Definition: typedefs.h:51
char * PCHAR
Definition: typedefs.h:51
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NO_SUCH_FILE
Definition: udferr_usr.h:137
#define STATUS_NO_MORE_FILES
Definition: udferr_usr.h:128
#define NT_ERROR(Status)
Definition: umtypes.h:106
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
#define SL_WATCH_TREE
Definition: iotypes.h:1839
#define SL_INDEX_SPECIFIED
Definition: iotypes.h:1837
#define SL_RETURN_SINGLE_ENTRY
Definition: iotypes.h:1836
#define SL_RESTART_SCAN
Definition: iotypes.h:1835
#define NT_ASSERT
Definition: rtlfuncs.h:3310
__wchar_t WCHAR
Definition: xmlstorage.h:180