Windows: AFSRedirLib.sys file system library driver
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSGeneric.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSGeneric.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSExceptionFilter
43 //
44 // Description:
45 //
46 //      This function is the exception handler
47 //
48 // Return:
49 //
50 //      A status is returned for the function
51 //
52
53 ULONG
54 AFSExceptionFilter( IN ULONG Code,
55                     IN PEXCEPTION_POINTERS ExceptPtrs)
56 {
57
58     PEXCEPTION_RECORD ExceptRec;
59     PCONTEXT Context;
60
61     __try
62     {
63
64         ExceptRec = ExceptPtrs->ExceptionRecord;
65
66         Context = ExceptPtrs->ContextRecord;
67
68         AFSDbgLogMsg( 0,
69                       0,
70                       "AFSExceptionFilter (Library) - EXR %p CXR %p Code %08lX Address %p Routine %p\n",
71                       ExceptRec,
72                       Context,
73                       ExceptRec->ExceptionCode,
74                       ExceptRec->ExceptionAddress,
75                       (void *)AFSExceptionFilter);
76
77         DbgPrint("**** Exception Caught in AFS Redirector Library ****\n");
78
79         DbgPrint("\n\nPerform the following WnDbg Cmds:\n");
80         DbgPrint("\n\t.exr %p ;  .cxr %p\n\n", ExceptRec, Context);
81
82         DbgPrint("**** Exception Complete from AFS Redirector Library ****\n");
83
84         if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_BUGCHECK_EXCEPTION))
85         {
86
87             KeBugCheck( (ULONG)-2);
88         }
89         else
90         {
91
92             AFSBreakPoint();
93         }
94     }
95     __except( EXCEPTION_EXECUTE_HANDLER)
96     {
97
98         NOTHING;
99     }
100
101     return EXCEPTION_EXECUTE_HANDLER;
102 }
103
104 //
105 // Function: AFSLibExAllocatePoolWithTag()
106 //
107 // Purpose: Allocate Pool Memory.  If BugCheck Exception flag
108 //          is configured on, then bugcheck the system if
109 //          a memory allocation fails.  The routine should be
110 //          used for all memory allocations that are to be freed
111 //          when the library is unloaded.  Memory allocations that
112 //          are to survive library unload and reload should be
113 //          performed using AFSExAllocatePoolWithTag() which is
114 //          provided by the AFS Framework.
115 //
116 // Parameters:
117 //                POOL_TYPE PoolType - Paged or NonPaged
118 //                SIZE_T NumberOfBytes - requested allocation size
119 //                ULONG  Tag - Pool Allocation Tag to be applied for tracking
120 //
121 // Return:
122 //                void * - the memory allocation
123 //
124
125 void *
126 AFSLibExAllocatePoolWithTag( IN POOL_TYPE  PoolType,
127                              IN SIZE_T  NumberOfBytes,
128                              IN ULONG  Tag)
129 {
130
131     void *pBuffer = NULL;
132
133     pBuffer = ExAllocatePoolWithTag( PoolType,
134                                      NumberOfBytes,
135                                      Tag);
136
137     if( pBuffer == NULL)
138     {
139
140         if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_BUGCHECK_EXCEPTION))
141         {
142
143             KeBugCheck( (ULONG)-2);
144         }
145         else
146         {
147
148             AFSDbgLogMsg( 0,
149                           0,
150                           "AFSLibExAllocatePoolWithTag failure Type %08lX Size %08lX Tag %08lX %08lX\n",
151                           PoolType,
152                           NumberOfBytes,
153                           Tag,
154                           PsGetCurrentThread());
155
156             AFSBreakPoint();
157         }
158     }
159
160     return pBuffer;
161 }
162
163 //
164 // Function: AFSAcquireExcl()
165 //
166 // Purpose: Called to acquire a resource exclusive with optional wait
167 //
168 // Parameters:
169 //                PERESOURCE Resource - Resource to acquire
170 //                BOOLEAN Wait - Whether to block
171 //
172 // Return:
173 //                BOOLEAN - Whether the mask was acquired
174 //
175
176 BOOLEAN
177 AFSAcquireExcl( IN PERESOURCE Resource,
178                 IN BOOLEAN wait)
179 {
180
181     BOOLEAN bStatus = FALSE;
182
183     //
184     // Normal kernel APCs must be disabled before calling
185     // ExAcquireResourceExclusiveLite. Otherwise a bugcheck occurs.
186     //
187
188     KeEnterCriticalRegion();
189
190     bStatus = ExAcquireResourceExclusiveLite( Resource,
191                                               wait);
192
193     if( !bStatus)
194     {
195
196         KeLeaveCriticalRegion();
197     }
198
199     return bStatus;
200 }
201
202 BOOLEAN
203 AFSAcquireSharedStarveExclusive( IN PERESOURCE Resource,
204                                  IN BOOLEAN Wait)
205 {
206
207     BOOLEAN bStatus = FALSE;
208
209     KeEnterCriticalRegion();
210
211     bStatus = ExAcquireSharedStarveExclusive( Resource,
212                                               Wait);
213
214     if( !bStatus)
215     {
216
217         KeLeaveCriticalRegion();
218     }
219
220     return bStatus;
221 }
222
223 //
224 // Function: AFSAcquireShared()
225 //
226 // Purpose: Called to acquire a resource shared with optional wait
227 //
228 // Parameters:
229 //                PERESOURCE Resource - Resource to acquire
230 //                BOOLEAN Wait - Whether to block
231 //
232 // Return:
233 //                BOOLEAN - Whether the mask was acquired
234 //
235
236 BOOLEAN
237 AFSAcquireShared( IN PERESOURCE Resource,
238                   IN BOOLEAN wait)
239 {
240
241     BOOLEAN bStatus = FALSE;
242
243     KeEnterCriticalRegion();
244
245     bStatus = ExAcquireResourceSharedLite( Resource,
246                                            wait);
247
248     if( !bStatus)
249     {
250
251         KeLeaveCriticalRegion();
252     }
253
254     return bStatus;
255 }
256
257 //
258 // Function: AFSReleaseResource()
259 //
260 // Purpose: Called to release a resource
261 //
262 // Parameters:
263 //                PERESOURCE Resource - Resource to release
264 //
265 // Return:
266 //                None
267 //
268
269 void
270 AFSReleaseResource( IN PERESOURCE Resource)
271 {
272
273     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
274                   AFS_TRACE_LEVEL_VERBOSE,
275                   "AFSReleaseResource Releasing lock %08lX Thread %08lX\n",
276                   Resource,
277                   PsGetCurrentThread());
278
279     ExReleaseResourceLite( Resource);
280
281     KeLeaveCriticalRegion();
282
283     return;
284 }
285
286 void
287 AFSConvertToShared( IN PERESOURCE Resource)
288 {
289
290     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
291                   AFS_TRACE_LEVEL_VERBOSE,
292                   "AFSConvertToShared Converting lock %08lX Thread %08lX\n",
293                   Resource,
294                   PsGetCurrentThread());
295
296     ExConvertExclusiveToSharedLite( Resource);
297
298     return;
299 }
300
301 //
302 // Function: AFSCompleteRequest
303 //
304 // Description:
305 //
306 //      This function completes irps
307 //
308 // Return:
309 //
310 //      A status is returned for the function
311 //
312
313 void
314 AFSCompleteRequest( IN PIRP Irp,
315                     IN ULONG Status)
316 {
317
318     Irp->IoStatus.Status = Status;
319
320     IoCompleteRequest( Irp,
321                        IO_NO_INCREMENT);
322
323     return;
324 }
325
326 //
327 // Function: AFSBuildCRCTable
328 //
329 // Description:
330 //
331 //      This function builds the CRC table for mapping filenames to a CRC value.
332 //
333 // Return:
334 //
335 //      A status is returned for the function
336 //
337
338 void
339 AFSBuildCRCTable()
340 {
341     ULONG crc;
342     int i, j;
343
344     for ( i = 0; i <= 255; i++)
345     {
346         crc = i;
347         for ( j = 8; j > 0; j--)
348         {
349             if (crc & 1)
350             {
351                 crc = ( crc >> 1 ) ^ CRC32_POLYNOMIAL;
352             }
353             else
354             {
355                 crc >>= 1;
356             }
357         }
358
359         AFSCRCTable[ i ] = crc;
360     }
361 }
362
363 //
364 // Function: AFSGenerateCRC
365 //
366 // Description:
367 //
368 //      Given a device and filename this function generates a CRC
369 //
370 // Return:
371 //
372 //      A status is returned for the function
373 //
374
375 ULONG
376 AFSGenerateCRC( IN PUNICODE_STRING FileName,
377                 IN BOOLEAN UpperCaseName)
378 {
379
380     ULONG crc;
381     ULONG temp1, temp2;
382     UNICODE_STRING UpcaseString;
383     WCHAR *lpbuffer;
384     USHORT size = 0;
385
386     if( !AFSCRCTable[1])
387     {
388         AFSBuildCRCTable();
389     }
390
391     crc = 0xFFFFFFFFL;
392
393     if( UpperCaseName)
394     {
395
396         RtlUpcaseUnicodeString( &UpcaseString,
397                                 FileName,
398                                 TRUE);
399
400         lpbuffer = UpcaseString.Buffer;
401
402         size = (UpcaseString.Length/sizeof( WCHAR));
403     }
404     else
405     {
406
407         lpbuffer = FileName->Buffer;
408
409         size = (FileName->Length/sizeof( WCHAR));
410     }
411
412     while (size--)
413     {
414         temp1 = (crc >> 8) & 0x00FFFFFFL;
415         temp2 = AFSCRCTable[((int)crc ^ *lpbuffer++) & 0xff];
416         crc = temp1 ^ temp2;
417     }
418
419     if( UpperCaseName)
420     {
421
422         RtlFreeUnicodeString( &UpcaseString);
423     }
424
425     crc ^= 0xFFFFFFFFL;
426
427     return crc;
428 }
429
430 void *
431 AFSLockSystemBuffer( IN PIRP Irp,
432                      IN ULONG Length)
433 {
434
435     NTSTATUS Status = STATUS_SUCCESS;
436     void *pAddress = NULL;
437
438     if( Irp->MdlAddress != NULL)
439     {
440
441         pAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress,
442                                                  NormalPagePriority);
443     }
444     else if( Irp->AssociatedIrp.SystemBuffer != NULL)
445     {
446
447         pAddress = Irp->AssociatedIrp.SystemBuffer;
448     }
449     else if( Irp->UserBuffer != NULL)
450     {
451
452         Irp->MdlAddress = IoAllocateMdl( Irp->UserBuffer,
453                                          Length,
454                                          FALSE,
455                                          FALSE,
456                                          Irp);
457
458         if( Irp->MdlAddress != NULL)
459         {
460
461             //
462             //  Lock the new Mdl in memory.
463             //
464
465             __try
466             {
467                 PIO_STACK_LOCATION pIoStack;
468                 pIoStack = IoGetCurrentIrpStackLocation( Irp);
469
470
471                 MmProbeAndLockPages( Irp->MdlAddress, KernelMode,
472                                      (pIoStack->MajorFunction == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess);
473
474                 pAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
475
476             }
477             __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
478             {
479
480                 IoFreeMdl( Irp->MdlAddress );
481                 Irp->MdlAddress = NULL;
482                 pAddress = NULL;
483             }
484         }
485     }
486
487     return pAddress;
488 }
489
490 void *
491 AFSLockUserBuffer( IN void *UserBuffer,
492                    IN ULONG BufferLength,
493                                    OUT MDL ** Mdl)
494 {
495
496     NTSTATUS ntStatus = STATUS_SUCCESS;
497     void *pAddress = NULL;
498         MDL *pMdl = NULL;
499
500         __Enter
501         {
502
503         pMdl = IoAllocateMdl( UserBuffer,
504                               BufferLength,
505                               FALSE,
506                               FALSE,
507                               NULL);
508
509                 if( pMdl == NULL)
510                 {
511
512                         try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
513                 }
514
515         //
516         //  Lock the new Mdl in memory.
517         //
518
519         __try
520         {
521
522             MmProbeAndLockPages( pMdl,
523                                                                  KernelMode,
524                                  IoWriteAccess);
525
526             pAddress = MmGetSystemAddressForMdlSafe( pMdl,
527                                                                                                          NormalPagePriority);
528         }
529         __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
530         {
531
532             IoFreeMdl( pMdl);
533             pMdl = NULL;
534             pAddress = NULL;
535         }
536
537                 if( pMdl != NULL)
538                 {
539
540                         *Mdl = pMdl;
541                 }
542
543 try_exit:
544
545         NOTHING;
546     }
547
548     return pAddress;
549 }
550
551 void *
552 AFSMapToService( IN PIRP Irp,
553                  IN ULONG ByteCount)
554 {
555
556     NTSTATUS ntStatus = STATUS_SUCCESS;
557     void *pMappedBuffer = NULL;
558     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
559     KAPC stApcState;
560
561     __Enter
562     {
563
564         if( pDevExt->Specific.Control.ServiceProcess == NULL)
565         {
566
567             try_return( ntStatus = STATUS_DEVICE_NOT_READY);
568         }
569
570         if( Irp->MdlAddress == NULL)
571         {
572
573             if( AFSLockSystemBuffer( Irp,
574                                      ByteCount) == NULL)
575             {
576
577                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
578             }
579         }
580
581         //
582         // Attach to the service process for mapping
583         //
584
585         KeStackAttachProcess( pDevExt->Specific.Control.ServiceProcess,
586                               (PRKAPC_STATE)&stApcState);
587
588         pMappedBuffer = MmMapLockedPagesSpecifyCache( Irp->MdlAddress,
589                                                       UserMode,
590                                                       MmCached,
591                                                       NULL,
592                                                       FALSE,
593                                                       NormalPagePriority);
594
595         KeUnstackDetachProcess( (PRKAPC_STATE)&stApcState);
596
597 try_exit:
598
599         NOTHING;
600     }
601
602     return pMappedBuffer;
603 }
604
605 NTSTATUS
606 AFSUnmapServiceMappedBuffer( IN void *MappedBuffer,
607                              IN PMDL Mdl)
608 {
609
610     NTSTATUS ntStatus = STATUS_SUCCESS;
611     void *pMappedBuffer = NULL;
612     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
613     KAPC stApcState;
614
615     __Enter
616     {
617
618         if( pDevExt->Specific.Control.ServiceProcess == NULL)
619         {
620
621             try_return( ntStatus = STATUS_DEVICE_NOT_READY);
622         }
623
624         if( Mdl != NULL)
625         {
626
627             //
628             // Attach to the service process for mapping
629             //
630
631             KeStackAttachProcess( pDevExt->Specific.Control.ServiceProcess,
632                                   (PRKAPC_STATE)&stApcState);
633
634             MmUnmapLockedPages( MappedBuffer,
635                                 Mdl);
636
637             KeUnstackDetachProcess( (PRKAPC_STATE)&stApcState);
638         }
639
640 try_exit:
641
642         NOTHING;
643     }
644
645     return ntStatus;
646 }
647
648 NTSTATUS
649 AFSInitializeLibraryDevice()
650 {
651
652     NTSTATUS ntStatus = STATUS_SUCCESS;
653     AFSDeviceExt *pDeviceExt = NULL;
654
655     __Enter
656     {
657
658         pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
659
660         //
661         // The PIOCtl file name
662         //
663
664         RtlInitUnicodeString( &AFSPIOCtlName,
665                               AFS_PIOCTL_FILE_INTERFACE_NAME);
666
667         //
668         // And the global root share name
669         //
670
671         RtlInitUnicodeString( &AFSGlobalRootName,
672                               AFS_GLOBAL_ROOT_SHARE_NAME);
673
674     }
675
676     return ntStatus;
677 }
678
679 NTSTATUS
680 AFSRemoveLibraryDevice()
681 {
682
683     NTSTATUS ntStatus = STATUS_SUCCESS;
684
685     __Enter
686     {
687
688     }
689
690     return ntStatus;
691 }
692
693 NTSTATUS
694 AFSDefaultDispatch( IN PDEVICE_OBJECT DeviceObject,
695                     IN PIRP Irp)
696 {
697
698     NTSTATUS            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
699     PIO_STACK_LOCATION  pIrpSp = IoGetCurrentIrpStackLocation( Irp);
700
701     AFSCompleteRequest( Irp,
702                         ntStatus);
703
704     return ntStatus;
705 }
706
707 NTSTATUS
708 AFSInitializeGlobalDirectoryEntries()
709 {
710
711     NTSTATUS ntStatus = STATUS_SUCCESS;
712     AFSDirectoryCB *pDirNode = NULL;
713     ULONG ulEntryLength = 0;
714     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
715     AFSObjectInfoCB *pObjectInfoCB = NULL;
716     AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL;
717
718     __Enter
719     {
720
721         //
722         // Initialize the global . entry
723         //
724
725         pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation,
726                                                0);
727
728         if( pObjectInfoCB == NULL)
729         {
730
731             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
732                           AFS_TRACE_LEVEL_ERROR,
733                           "AFSInitializeGlobalDirectory AFSAllocateObjectInfo failure %08lX\n",
734                           ntStatus);
735
736             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
737         }
738
739         InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount);
740
741         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
742                       AFS_TRACE_LEVEL_VERBOSE,
743                       "AFSInitializeGlobalDirectoryEntries Increment count on object %08lX Cnt %d\n",
744                       pObjectInfoCB,
745                       pObjectInfoCB->ObjectReferenceCount);
746
747         ntStatus = STATUS_SUCCESS;
748
749         ulEntryLength = sizeof( AFSDirectoryCB) +
750                                      sizeof( WCHAR);
751
752         pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool,
753                                                                   ulEntryLength,
754                                                                   AFS_DIR_ENTRY_TAG);
755
756         if( pDirNode == NULL)
757         {
758
759             AFSDeleteObjectInfo( pObjectInfoCB);
760
761             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
762                           AFS_TRACE_LEVEL_ERROR,
763                           "AFSInitializeGlobalDirectory AFS_DIR_ENTRY_TAG allocation failure\n");
764
765             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
766         }
767
768         pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool,
769                                                                                    sizeof( AFSNonPagedDirectoryCB),
770                                                                                    AFS_DIR_ENTRY_NP_TAG);
771
772         if( pNonPagedDirEntry == NULL)
773         {
774
775             ExFreePool( pDirNode);
776
777             AFSDeleteObjectInfo( pObjectInfoCB);
778
779             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
780                           AFS_TRACE_LEVEL_ERROR,
781                           "AFSInitializeGlobalDirectory AFS_DIR_ENTRY_NP_TAG allocation failure\n");
782
783             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
784         }
785
786         RtlZeroMemory( pDirNode,
787                        ulEntryLength);
788
789         RtlZeroMemory( pNonPagedDirEntry,
790                        sizeof( AFSNonPagedDirectoryCB));
791
792         ExInitializeResourceLite( &pNonPagedDirEntry->Lock);
793
794         pDirNode->NonPaged = pNonPagedDirEntry;
795
796         pDirNode->ObjectInformation = pObjectInfoCB;
797
798         //
799         // Set valid entry
800         //
801
802         SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE | AFS_DIR_ENTRY_FAKE | AFS_DIR_ENTRY_VALID);
803
804         pDirNode->FileIndex = (ULONG)AFS_DIR_ENTRY_DOT_INDEX;
805
806         //
807         // Setup the names in the entry
808         //
809
810         pDirNode->NameInformation.FileName.Length = sizeof( WCHAR);
811
812         pDirNode->NameInformation.FileName.MaximumLength = sizeof( WCHAR);
813
814         pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB));
815
816         pDirNode->NameInformation.FileName.Buffer[ 0] = L'.';
817
818         //
819         // Populate the rest of the data
820         //
821
822         pObjectInfoCB->FileType = AFS_FILE_TYPE_DIRECTORY;
823
824         pObjectInfoCB->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
825
826         AFSGlobalDotDirEntry = pDirNode;
827
828         //
829         // Now the .. entry
830         //
831
832         pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation,
833                                                0);
834
835         if( pObjectInfoCB == NULL)
836         {
837
838             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
839                           AFS_TRACE_LEVEL_ERROR,
840                           "AFSInitializeGlobalDirectory AFSAllocateObjectInfo (2) failure %08lX\n",
841                           ntStatus);
842
843             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
844         }
845
846         InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount);
847
848         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
849                       AFS_TRACE_LEVEL_VERBOSE,
850                       "AFSInitializeGlobalDirectoryEntries Increment count on object %08lX Cnt %d\n",
851                       pObjectInfoCB,
852                       pObjectInfoCB->ObjectReferenceCount);
853
854         ntStatus = STATUS_SUCCESS;
855
856         ulEntryLength = sizeof( AFSDirectoryCB) +
857                                      ( 2 * sizeof( WCHAR));
858
859         pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool,
860                                                                   ulEntryLength,
861                                                                   AFS_DIR_ENTRY_TAG);
862
863         if( pDirNode == NULL)
864         {
865
866             AFSDeleteObjectInfo( pObjectInfoCB);
867
868             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
869         }
870
871         pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool,
872                                                                                    sizeof( AFSNonPagedDirectoryCB),
873                                                                                    AFS_DIR_ENTRY_NP_TAG);
874
875         if( pNonPagedDirEntry == NULL)
876         {
877
878             ExFreePool( pDirNode);
879
880             AFSDeleteObjectInfo( pObjectInfoCB);
881
882             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
883         }
884
885         RtlZeroMemory( pDirNode,
886                        ulEntryLength);
887
888         RtlZeroMemory( pNonPagedDirEntry,
889                        sizeof( AFSNonPagedDirectoryCB));
890
891         ExInitializeResourceLite( &pNonPagedDirEntry->Lock);
892
893         pDirNode->NonPaged = pNonPagedDirEntry;
894
895         pDirNode->ObjectInformation = pObjectInfoCB;
896
897         //
898         // Set valid entry
899         //
900
901         SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE | AFS_DIR_ENTRY_FAKE | AFS_DIR_ENTRY_VALID);
902
903         pDirNode->FileIndex = (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX;
904
905         //
906         // Setup the names in the entry
907         //
908
909         pDirNode->NameInformation.FileName.Length = 2 * sizeof( WCHAR);
910
911         pDirNode->NameInformation.FileName.MaximumLength = 2 * sizeof( WCHAR);
912
913         pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB));
914
915         pDirNode->NameInformation.FileName.Buffer[ 0] = L'.';
916
917         pDirNode->NameInformation.FileName.Buffer[ 1] = L'.';
918
919         //
920         // Populate the rest of the data
921         //
922
923         pObjectInfoCB->FileType = AFS_FILE_TYPE_DIRECTORY;
924
925         pObjectInfoCB->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
926
927         AFSGlobalDotDotDirEntry = pDirNode;
928
929 try_exit:
930
931         if( !NT_SUCCESS( ntStatus))
932         {
933
934             if( AFSGlobalDotDirEntry != NULL)
935             {
936
937                 AFSDeleteObjectInfo( AFSGlobalDotDirEntry->ObjectInformation);
938
939                 ExDeleteResourceLite( &AFSGlobalDotDirEntry->NonPaged->Lock);
940
941                 ExFreePool( AFSGlobalDotDirEntry->NonPaged);
942
943                 ExFreePool( AFSGlobalDotDirEntry);
944
945                 AFSGlobalDotDirEntry = NULL;
946             }
947
948             if( AFSGlobalDotDotDirEntry != NULL)
949             {
950
951                 AFSDeleteObjectInfo( AFSGlobalDotDotDirEntry->ObjectInformation);
952
953                 ExDeleteResourceLite( &AFSGlobalDotDotDirEntry->NonPaged->Lock);
954
955                 ExFreePool( AFSGlobalDotDotDirEntry->NonPaged);
956
957                 ExFreePool( AFSGlobalDotDotDirEntry);
958
959                 AFSGlobalDotDotDirEntry = NULL;
960             }
961         }
962     }
963
964     return ntStatus;
965 }
966
967 AFSDirectoryCB *
968 AFSInitDirEntry( IN AFSObjectInfoCB *ParentObjectInfo,
969                  IN PUNICODE_STRING FileName,
970                  IN PUNICODE_STRING TargetName,
971                  IN AFSDirEnumEntry *DirEnumEntry,
972                  IN ULONG FileIndex)
973 {
974
975     AFSDirectoryCB *pDirNode = NULL;
976     NTSTATUS ntStatus = STATUS_SUCCESS;
977     ULONG ulEntryLength = 0;
978     AFSDirEnumEntry *pDirEnumCB = NULL;
979     AFSFileID stTargetFileID;
980     AFSFcb *pVcb = NULL;
981     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
982     AFSObjectInfoCB *pObjectInfoCB = NULL;
983     BOOLEAN bAllocatedObjectCB = FALSE;
984     ULONGLONG ullIndex = 0;
985     AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL;
986
987     __Enter
988     {
989
990         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
991                       AFS_TRACE_LEVEL_VERBOSE,
992                       "AFSInitDirEntry Initializing entry %wZ parent FID %08lX-%08lX-%08lX-%08lX\n",
993                       FileName,
994                       ParentObjectInfo->FileId.Cell,
995                       ParentObjectInfo->FileId.Volume,
996                       ParentObjectInfo->FileId.Vnode,
997                       ParentObjectInfo->FileId.Unique);
998
999         //
1000         // First thing is to locate/create our object information block
1001         // for this entry
1002         //
1003
1004         AFSAcquireExcl( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
1005                         TRUE);
1006
1007         ullIndex = AFSCreateLowIndex( &DirEnumEntry->FileId);
1008
1009         ntStatus = AFSLocateHashEntry( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
1010                                        ullIndex,
1011                                        (AFSBTreeEntry **)&pObjectInfoCB);
1012
1013         if( !NT_SUCCESS( ntStatus) ||
1014             pObjectInfoCB == NULL)
1015         {
1016
1017             //
1018             // Allocate our object info cb
1019             //
1020
1021             pObjectInfoCB = AFSAllocateObjectInfo( ParentObjectInfo,
1022                                                    ullIndex);
1023
1024             if( pObjectInfoCB == NULL)
1025             {
1026
1027                 AFSReleaseResource( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
1028
1029                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1030             }
1031
1032             bAllocatedObjectCB = TRUE;
1033
1034             AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1035                           AFS_TRACE_LEVEL_VERBOSE,
1036                           "AFSInitDirEntry initialized object %08lX Parent Object %08lX for %wZ\n",
1037                           pObjectInfoCB,
1038                           ParentObjectInfo,
1039                           FileName);
1040         }
1041
1042         InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount);
1043
1044         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1045                       AFS_TRACE_LEVEL_VERBOSE,
1046                       "AFSInitDirEntry Increment count on object %08lX Cnt %d\n",
1047                       pObjectInfoCB,
1048                       pObjectInfoCB->ObjectReferenceCount);
1049
1050         AFSReleaseResource( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
1051
1052         ntStatus = STATUS_SUCCESS;
1053
1054         ulEntryLength = sizeof( AFSDirectoryCB) +
1055                                      FileName->Length;
1056
1057         if( TargetName != NULL)
1058         {
1059
1060             ulEntryLength += TargetName->Length;
1061         }
1062
1063         pDirNode = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool,
1064                                                                ulEntryLength,
1065                                                                AFS_DIR_ENTRY_TAG);
1066
1067         if( pDirNode == NULL)
1068         {
1069
1070             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1071         }
1072
1073         pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool,
1074                                                                                 sizeof( AFSNonPagedDirectoryCB),
1075                                                                                 AFS_DIR_ENTRY_NP_TAG);
1076
1077         if( pNonPagedDirEntry == NULL)
1078         {
1079
1080             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1081         }
1082
1083         RtlZeroMemory( pDirNode,
1084                        ulEntryLength);
1085
1086         RtlZeroMemory( pNonPagedDirEntry,
1087                        sizeof( AFSNonPagedDirectoryCB));
1088
1089         ExInitializeResourceLite( &pNonPagedDirEntry->Lock);
1090
1091         pDirNode->NonPaged = pNonPagedDirEntry;
1092
1093         pDirNode->ObjectInformation = pObjectInfoCB;
1094
1095         //
1096         // Set valid entry
1097         //
1098
1099         SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID);
1100
1101         pDirNode->FileIndex = FileIndex;
1102
1103         //
1104         // Setup the names in the entry
1105         //
1106
1107         if( FileName->Length > 0)
1108         {
1109
1110             pDirNode->NameInformation.FileName.Length = FileName->Length;
1111
1112             pDirNode->NameInformation.FileName.MaximumLength = FileName->Length;
1113
1114             pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB));
1115
1116             RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer,
1117                            FileName->Buffer,
1118                            pDirNode->NameInformation.FileName.Length);
1119
1120             //
1121             // Create a CRC for the file
1122             //
1123
1124             pDirNode->CaseSensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName,
1125                                                                          FALSE);
1126
1127             pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName,
1128                                                                            TRUE);
1129         }
1130
1131         if( TargetName != NULL &&
1132             TargetName->Length > 0)
1133         {
1134
1135             pDirNode->NameInformation.TargetName.Length = TargetName->Length;
1136
1137             pDirNode->NameInformation.TargetName.MaximumLength = pDirNode->NameInformation.TargetName.Length;
1138
1139             pDirNode->NameInformation.TargetName.Buffer = (WCHAR *)((char *)pDirNode +
1140                                                                             sizeof( AFSDirectoryCB) +
1141                                                                             pDirNode->NameInformation.FileName.Length);
1142
1143             RtlCopyMemory( pDirNode->NameInformation.TargetName.Buffer,
1144                            TargetName->Buffer,
1145                            pDirNode->NameInformation.TargetName.Length);
1146         }
1147
1148         //
1149         // If we allocated the object information cb then update the information
1150         //
1151
1152         if( bAllocatedObjectCB)
1153         {
1154
1155             //
1156             // Populate the rest of the data
1157             //
1158
1159             pObjectInfoCB->FileId = DirEnumEntry->FileId;
1160
1161             pObjectInfoCB->TargetFileId = DirEnumEntry->TargetFileId;
1162
1163             pObjectInfoCB->FileType = DirEnumEntry->FileType;
1164
1165             pObjectInfoCB->CreationTime = DirEnumEntry->CreationTime;
1166
1167             pObjectInfoCB->LastAccessTime = DirEnumEntry->LastAccessTime;
1168
1169             pObjectInfoCB->LastWriteTime = DirEnumEntry->LastWriteTime;
1170
1171             pObjectInfoCB->ChangeTime = DirEnumEntry->ChangeTime;
1172
1173             pObjectInfoCB->EndOfFile = DirEnumEntry->EndOfFile;
1174
1175             pObjectInfoCB->AllocationSize = DirEnumEntry->AllocationSize;
1176
1177             pObjectInfoCB->FileAttributes = DirEnumEntry->FileAttributes;
1178
1179             if( pObjectInfoCB->FileType == AFS_FILE_TYPE_MOUNTPOINT ||
1180                 pObjectInfoCB->FileType == AFS_FILE_TYPE_SYMLINK ||
1181                 pObjectInfoCB->FileType == AFS_FILE_TYPE_DFSLINK)
1182             {
1183
1184                 pObjectInfoCB->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1185             }
1186
1187             pObjectInfoCB->EaSize = DirEnumEntry->EaSize;
1188
1189             //
1190             // Object specific information
1191             //
1192
1193             pObjectInfoCB->Links = DirEnumEntry->Links;
1194
1195             pObjectInfoCB->Expiration = DirEnumEntry->Expiration;
1196
1197             pObjectInfoCB->DataVersion = DirEnumEntry->DataVersion;
1198
1199             //
1200             // Check for the case where we have a filetype of SymLink but both the TargetFid and the
1201             // TargetName are empty. In this case set the filetype to zero so we evaluate it later in
1202             // the code
1203             //
1204
1205             if( pObjectInfoCB->FileType == AFS_FILE_TYPE_SYMLINK &&
1206                 pObjectInfoCB->TargetFileId.Vnode == 0 &&
1207                 pObjectInfoCB->TargetFileId.Unique == 0 &&
1208                 pDirNode->NameInformation.TargetName.Length == 0)
1209             {
1210
1211                 //
1212                 // This will ensure we perform a validation on the node
1213                 //
1214
1215                 pObjectInfoCB->FileType = AFS_FILE_TYPE_UNKNOWN;
1216             }
1217
1218             if( pObjectInfoCB->FileType == AFS_FILE_TYPE_UNKNOWN)
1219             {
1220
1221                 SetFlag( pObjectInfoCB->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED);
1222             }
1223         }
1224
1225 try_exit:
1226
1227         if( !NT_SUCCESS( ntStatus))
1228         {
1229
1230             if( pNonPagedDirEntry != NULL)
1231             {
1232
1233                 ExDeleteResourceLite( &pNonPagedDirEntry->Lock);
1234
1235                 AFSExFreePool( pNonPagedDirEntry);
1236             }
1237
1238             if( pDirNode != NULL)
1239             {
1240
1241                 AFSExFreePool( pDirNode);
1242
1243                 pDirNode = NULL;
1244             }
1245
1246             //
1247             // Dereference our object info block if we have one
1248             //
1249
1250             if( pObjectInfoCB != NULL)
1251             {
1252
1253                 InterlockedDecrement( &pObjectInfoCB->ObjectReferenceCount);
1254
1255                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1256                               AFS_TRACE_LEVEL_VERBOSE,
1257                               "AFSInitDirEntry Decrement count on object %08lX Cnt %d\n",
1258                               pObjectInfoCB,
1259                               pObjectInfoCB->ObjectReferenceCount);
1260
1261                 if( bAllocatedObjectCB)
1262                 {
1263
1264                     ASSERT( pObjectInfoCB->ObjectReferenceCount == 0);
1265
1266                     AFSDeleteObjectInfo( pObjectInfoCB);
1267                 }
1268             }
1269         }
1270     }
1271
1272     return pDirNode;
1273 }
1274
1275 BOOLEAN
1276 AFSCheckForReadOnlyAccess( IN ACCESS_MASK DesiredAccess,
1277                            IN BOOLEAN DirectoryEntry)
1278 {
1279
1280     BOOLEAN bReturn = TRUE;
1281     ACCESS_MASK stAccessMask = 0;
1282
1283     //
1284     // Get rid of anything we don't know about
1285     //
1286
1287     DesiredAccess = (DesiredAccess   &
1288                           ( DELETE |
1289                             READ_CONTROL |
1290                             WRITE_OWNER |
1291                             WRITE_DAC |
1292                             SYNCHRONIZE |
1293                             ACCESS_SYSTEM_SECURITY |
1294                             FILE_WRITE_DATA |
1295                             FILE_READ_EA |
1296                             FILE_WRITE_EA |
1297                             FILE_READ_ATTRIBUTES |
1298                             FILE_WRITE_ATTRIBUTES |
1299                             FILE_LIST_DIRECTORY |
1300                             FILE_TRAVERSE |
1301                             FILE_DELETE_CHILD |
1302                             FILE_APPEND_DATA));
1303
1304     //
1305     // Our 'read only' access mask. These are the accesses we will
1306     // allow for a read only file
1307     //
1308
1309     stAccessMask = DELETE |
1310                         READ_CONTROL |
1311                         WRITE_OWNER |
1312                         WRITE_DAC |
1313                         SYNCHRONIZE |
1314                         ACCESS_SYSTEM_SECURITY |
1315                         FILE_READ_DATA |
1316                         FILE_READ_EA |
1317                         FILE_WRITE_EA |
1318                         FILE_READ_ATTRIBUTES |
1319                         FILE_WRITE_ATTRIBUTES |
1320                         FILE_EXECUTE |
1321                         FILE_LIST_DIRECTORY |
1322                         FILE_TRAVERSE;
1323
1324     //
1325     // For a directory, add in the directory specific accesses
1326     //
1327
1328     if( DirectoryEntry)
1329     {
1330
1331         stAccessMask |= FILE_ADD_SUBDIRECTORY |
1332                                 FILE_ADD_FILE |
1333                                 FILE_DELETE_CHILD;
1334     }
1335
1336     if( FlagOn( DesiredAccess, ~stAccessMask))
1337     {
1338
1339         //
1340         // A write access is set ...
1341         //
1342
1343         bReturn = FALSE;
1344     }
1345
1346     return bReturn;
1347 }
1348
1349 NTSTATUS
1350 AFSEvaluateNode( IN GUID *AuthGroup,
1351                  IN AFSDirectoryCB *DirEntry)
1352 {
1353
1354     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1355     NTSTATUS ntStatus = STATUS_SUCCESS;
1356     AFSDirEnumEntry *pDirEntry = NULL;
1357     UNICODE_STRING uniTargetName;
1358
1359     __Enter
1360     {
1361
1362         ntStatus = AFSEvaluateTargetByID( DirEntry->ObjectInformation,
1363                                           AuthGroup,
1364                                           FALSE,
1365                                           &pDirEntry);
1366
1367         if( !NT_SUCCESS( ntStatus))
1368         {
1369
1370             try_return( ntStatus);
1371         }
1372
1373         DirEntry->ObjectInformation->TargetFileId = pDirEntry->TargetFileId;
1374
1375         DirEntry->ObjectInformation->Expiration = pDirEntry->Expiration;
1376
1377         DirEntry->ObjectInformation->DataVersion = pDirEntry->DataVersion;
1378
1379         DirEntry->ObjectInformation->FileType = pDirEntry->FileType;
1380
1381         DirEntry->ObjectInformation->CreationTime = pDirEntry->CreationTime;
1382
1383         DirEntry->ObjectInformation->LastAccessTime = pDirEntry->LastAccessTime;
1384
1385         DirEntry->ObjectInformation->LastWriteTime = pDirEntry->LastWriteTime;
1386
1387         DirEntry->ObjectInformation->ChangeTime = pDirEntry->ChangeTime;
1388
1389         DirEntry->ObjectInformation->EndOfFile = pDirEntry->EndOfFile;
1390
1391         DirEntry->ObjectInformation->AllocationSize = pDirEntry->AllocationSize;
1392
1393         DirEntry->ObjectInformation->FileAttributes = pDirEntry->FileAttributes;
1394
1395         DirEntry->ObjectInformation->EaSize = pDirEntry->EaSize;
1396
1397         DirEntry->ObjectInformation->Links = pDirEntry->Links;
1398
1399         //
1400         // If we have a target name then see if it needs updating ...
1401         //
1402
1403         if( pDirEntry->TargetNameLength > 0)
1404         {
1405
1406             //
1407             // Update the target name information if needed
1408             //
1409
1410             uniTargetName.Length = (USHORT)pDirEntry->TargetNameLength;
1411
1412             uniTargetName.MaximumLength = uniTargetName.Length;
1413
1414             uniTargetName.Buffer = (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset);
1415
1416             AFSAcquireExcl( &DirEntry->NonPaged->Lock,
1417                             TRUE);
1418
1419             if( DirEntry->NameInformation.TargetName.Length == 0 ||
1420                 RtlCompareUnicodeString( &uniTargetName,
1421                                          &DirEntry->NameInformation.TargetName,
1422                                          TRUE) != 0)
1423             {
1424
1425                 //
1426                 // Update the target name
1427                 //
1428
1429                 ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName,
1430                                                 &DirEntry->Flags,
1431                                                 uniTargetName.Buffer,
1432                                                 uniTargetName.Length);
1433
1434                 if( !NT_SUCCESS( ntStatus))
1435                 {
1436
1437                     AFSReleaseResource( &DirEntry->NonPaged->Lock);
1438
1439                     try_return( ntStatus);
1440                 }
1441             }
1442
1443             AFSReleaseResource( &DirEntry->NonPaged->Lock);
1444         }
1445
1446 try_exit:
1447
1448         if( pDirEntry != NULL)
1449         {
1450
1451             AFSExFreePool( pDirEntry);
1452         }
1453     }
1454
1455     return ntStatus;
1456 }
1457
1458 NTSTATUS
1459 AFSValidateSymLink( IN GUID *AuthGroup,
1460                     IN AFSDirectoryCB *DirEntry)
1461 {
1462
1463     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1464     NTSTATUS ntStatus = STATUS_SUCCESS;
1465     AFSDirEnumEntry *pDirEntry = NULL;
1466     UNICODE_STRING uniTargetName;
1467
1468     __Enter
1469     {
1470
1471         ntStatus = AFSEvaluateTargetByID( DirEntry->ObjectInformation,
1472                                           AuthGroup,
1473                                           FALSE,
1474                                           &pDirEntry);
1475
1476         if( !NT_SUCCESS( ntStatus))
1477         {
1478
1479             try_return( ntStatus);
1480         }
1481
1482         if( pDirEntry->FileType == AFS_FILE_TYPE_UNKNOWN ||
1483             pDirEntry->FileType == AFS_FILE_TYPE_INVALID)
1484         {
1485
1486             try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND);
1487         }
1488
1489         DirEntry->ObjectInformation->TargetFileId = pDirEntry->TargetFileId;
1490
1491         DirEntry->ObjectInformation->Expiration = pDirEntry->Expiration;
1492
1493         DirEntry->ObjectInformation->DataVersion = pDirEntry->DataVersion;
1494
1495         //
1496         // Update the target name information if needed
1497         //
1498
1499         uniTargetName.Length = (USHORT)pDirEntry->TargetNameLength;
1500
1501         uniTargetName.MaximumLength = uniTargetName.Length;
1502
1503         uniTargetName.Buffer = (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset);
1504
1505         if( uniTargetName.Length > 0)
1506         {
1507
1508             AFSAcquireExcl( &DirEntry->NonPaged->Lock,
1509                             TRUE);
1510
1511             if( DirEntry->NameInformation.TargetName.Length == 0 ||
1512                 RtlCompareUnicodeString( &uniTargetName,
1513                                          &DirEntry->NameInformation.TargetName,
1514                                          TRUE) != 0)
1515             {
1516
1517                 //
1518                 // Update the target name
1519                 //
1520
1521                 ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName,
1522                                                 &DirEntry->Flags,
1523                                                 uniTargetName.Buffer,
1524                                                 uniTargetName.Length);
1525
1526                 if( !NT_SUCCESS( ntStatus))
1527                 {
1528
1529                     AFSReleaseResource( &DirEntry->NonPaged->Lock);
1530
1531                     try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1532                 }
1533             }
1534
1535             AFSReleaseResource( &DirEntry->NonPaged->Lock);
1536         }
1537
1538         //
1539         // If the FileType is the same then nothing to do since it IS
1540         // a SymLink
1541         //
1542
1543         if( pDirEntry->FileType == DirEntry->ObjectInformation->FileType)
1544         {
1545
1546             ASSERT( pDirEntry->FileType == AFS_FILE_TYPE_SYMLINK);
1547
1548             try_return( ntStatus = STATUS_SUCCESS);
1549         }
1550
1551         DirEntry->ObjectInformation->FileType = pDirEntry->FileType;
1552
1553         DirEntry->ObjectInformation->CreationTime = pDirEntry->CreationTime;
1554
1555         DirEntry->ObjectInformation->LastAccessTime = pDirEntry->LastAccessTime;
1556
1557         DirEntry->ObjectInformation->LastWriteTime = pDirEntry->LastWriteTime;
1558
1559         DirEntry->ObjectInformation->ChangeTime = pDirEntry->ChangeTime;
1560
1561         DirEntry->ObjectInformation->EndOfFile = pDirEntry->EndOfFile;
1562
1563         DirEntry->ObjectInformation->AllocationSize = pDirEntry->AllocationSize;
1564
1565         DirEntry->ObjectInformation->FileAttributes = pDirEntry->FileAttributes;
1566
1567         DirEntry->ObjectInformation->EaSize = pDirEntry->EaSize;
1568
1569         DirEntry->ObjectInformation->Links = pDirEntry->Links;
1570
1571 try_exit:
1572
1573         if( pDirEntry != NULL)
1574         {
1575
1576             AFSExFreePool( pDirEntry);
1577         }
1578     }
1579
1580     return ntStatus;
1581 }
1582
1583 NTSTATUS
1584 AFSInvalidateCache( IN AFSInvalidateCacheCB *InvalidateCB)
1585 {
1586
1587     NTSTATUS ntStatus = STATUS_SUCCESS;
1588     AFSFcb      *pDcb = NULL, *pFcb = NULL, *pNextFcb = NULL;
1589     AFSVolumeCB *pVolumeCB = NULL;
1590     AFSFcb      *pTargetDcb = NULL;
1591     AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
1592     AFSDirectoryCB *pCurrentDirEntry = NULL;
1593     BOOLEAN     bIsChild = FALSE;
1594     ULONGLONG   ullIndex = 0;
1595     AFSObjectInfoCB *pObjectInfo = NULL;
1596     IO_STATUS_BLOCK stIoStatus;
1597     ULONG ulFilter = 0;
1598
1599     __Enter
1600     {
1601
1602         //
1603         // Need to locate the Fcb for the directory to purge
1604         //
1605
1606         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1607                       AFS_TRACE_LEVEL_VERBOSE,
1608                       "AFSInvalidateCache Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1609                       &pDevExt->Specific.RDR.VolumeTreeLock,
1610                       PsGetCurrentThread());
1611
1612         //
1613         // Starve any exclusive waiters on this paticular call
1614         //
1615
1616         AFSAcquireSharedStarveExclusive( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1617
1618         //
1619         // Locate the volume node
1620         //
1621
1622         ullIndex = AFSCreateHighIndex( &InvalidateCB->FileID);
1623
1624         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1625                                        ullIndex,
1626                                        (AFSBTreeEntry **)&pVolumeCB);
1627
1628         if( pVolumeCB != NULL)
1629         {
1630
1631             InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1632
1633             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1634                           AFS_TRACE_LEVEL_VERBOSE,
1635                           "AFSInvalidateCache Increment count on volume %08lX Cnt %d\n",
1636                           pVolumeCB,
1637                           pVolumeCB->VolumeReferenceCount);
1638         }
1639
1640         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1641
1642         if( !NT_SUCCESS( ntStatus) ||
1643             pVolumeCB == NULL)
1644         {
1645             try_return( ntStatus = STATUS_SUCCESS);
1646         }
1647
1648         //
1649         // If this is a whole volume invalidation then go do it now
1650         //
1651
1652         if( InvalidateCB->WholeVolume ||
1653             AFSIsVolumeFID( &InvalidateCB->FileID))
1654         {
1655
1656             ntStatus = AFSInvalidateVolume( pVolumeCB,
1657                                             InvalidateCB->Reason);
1658
1659             AFSFsRtlNotifyFullReportChange( &pVolumeCB->ObjectInformation,
1660                                             NULL,
1661                                             FILE_NOTIFY_CHANGE_FILE_NAME |
1662                                                 FILE_NOTIFY_CHANGE_DIR_NAME |
1663                                                 FILE_NOTIFY_CHANGE_NAME |
1664                                                 FILE_NOTIFY_CHANGE_ATTRIBUTES |
1665                                                 FILE_NOTIFY_CHANGE_SIZE,
1666                                             FILE_ACTION_MODIFIED);
1667
1668             InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1669
1670             try_return( ntStatus);
1671         }
1672
1673         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1674                           TRUE);
1675
1676         InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1677
1678         AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1679                       AFS_TRACE_LEVEL_VERBOSE,
1680                       "AFSInvalidateCache Decrement count on volume %08lX Cnt %d\n",
1681                       pVolumeCB,
1682                       pVolumeCB->VolumeReferenceCount);
1683
1684         ullIndex = AFSCreateLowIndex( &InvalidateCB->FileID);
1685
1686         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1687                                        ullIndex,
1688                                        (AFSBTreeEntry **)&pObjectInfo);
1689
1690         if( pObjectInfo != NULL)
1691         {
1692
1693             //
1694             // Reference the node so it won't be torn down
1695             //
1696
1697             InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1698
1699             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1700                           AFS_TRACE_LEVEL_VERBOSE,
1701                           "AFSInvalidateCache Increment count on object %08lX Cnt %d\n",
1702                           pObjectInfo,
1703                           pObjectInfo->ObjectReferenceCount);
1704         }
1705
1706         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1707
1708         if( !NT_SUCCESS( ntStatus) ||
1709             pObjectInfo == NULL)
1710         {
1711             try_return( ntStatus = STATUS_SUCCESS);
1712         }
1713
1714         if( pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK ||
1715             pObjectInfo->FileType == AFS_FILE_TYPE_DFSLINK ||
1716             pObjectInfo->FileType == AFS_FILE_TYPE_MOUNTPOINT)
1717         {
1718
1719             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1720                           AFS_TRACE_LEVEL_VERBOSE,
1721                           "AFSInvalidateCache Invalidation on node type %d for fid %08lX-%08lX-%08lX-%08lX Reason %d\n",
1722                           pObjectInfo->FileType,
1723                           pObjectInfo->FileId.Cell,
1724                           pObjectInfo->FileId.Volume,
1725                           pObjectInfo->FileId.Vnode,
1726                           pObjectInfo->FileId.Unique,
1727                           InvalidateCB->Reason);
1728
1729             //
1730             // We only act on the mount point itself, not the target. If the
1731             // node has been deleted then mark it as such otherwise indicate
1732             // it requires verification
1733             //
1734
1735             if( InvalidateCB->Reason == AFS_INVALIDATE_DELETED)
1736             {
1737                 SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID);
1738             }
1739             else
1740             {
1741
1742                 if( InvalidateCB->Reason == AFS_INVALIDATE_FLUSHED ||
1743                     InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION)
1744                 {
1745                     pObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1746                 }
1747
1748                 pObjectInfo->Expiration.QuadPart = 0;
1749
1750                 pObjectInfo->TargetFileId.Vnode = 0;
1751
1752                 pObjectInfo->TargetFileId.Unique = 0;
1753
1754                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1755                               AFS_TRACE_LEVEL_VERBOSE,
1756                               "AFSInvalidateCache Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n",
1757                               pObjectInfo->FileId.Cell,
1758                               pObjectInfo->FileId.Volume,
1759                               pObjectInfo->FileId.Vnode,
1760                               pObjectInfo->FileId.Unique);
1761
1762                 SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1763             }
1764
1765             ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME;
1766
1767             if( InvalidateCB->Reason == AFS_INVALIDATE_CREDS)
1768             {
1769                 ulFilter |= FILE_NOTIFY_CHANGE_SECURITY;
1770             }
1771
1772             if( InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION)
1773             {
1774                 ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
1775             }
1776             else
1777             {
1778                 ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
1779             }
1780
1781             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1782                                             NULL,
1783                                             FILE_NOTIFY_CHANGE_FILE_NAME |
1784                                             FILE_NOTIFY_CHANGE_ATTRIBUTES,
1785                                             FILE_ACTION_MODIFIED);
1786
1787             try_return( ntStatus);
1788         }
1789
1790         //
1791         // Depending on the reason for invalidation then perform work on the node
1792         //
1793
1794         switch( InvalidateCB->Reason)
1795         {
1796
1797             case AFS_INVALIDATE_DELETED:
1798             {
1799
1800                 //
1801                 // Mark this node as invalid
1802                 //
1803
1804                 SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED);
1805
1806                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1807                               AFS_TRACE_LEVEL_VERBOSE,
1808                               "AFSInvalidateCache Set DELETE flag on fid %08lX-%08lX-%08lX-%08lX\n",
1809                               pObjectInfo->FileId.Cell,
1810                               pObjectInfo->FileId.Volume,
1811                               pObjectInfo->FileId.Vnode,
1812                               pObjectInfo->FileId.Unique);
1813
1814                 if( pObjectInfo->ParentObjectInformation != NULL)
1815                 {
1816
1817                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1818                                   AFS_TRACE_LEVEL_VERBOSE,
1819                                   "AFSInvalidateCache Set VERIFY flag on parent fid %08lX-%08lX-%08lX-%08lX\n",
1820                                   pObjectInfo->ParentObjectInformation->FileId.Cell,
1821                                   pObjectInfo->ParentObjectInformation->FileId.Volume,
1822                                   pObjectInfo->ParentObjectInformation->FileId.Vnode,
1823                                   pObjectInfo->ParentObjectInformation->FileId.Unique);
1824
1825                     SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
1826                     pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
1827                     pObjectInfo->ParentObjectInformation->Expiration.QuadPart = 0;
1828                 }
1829
1830                 if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY)
1831                 {
1832                     ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME;
1833                 }
1834                 else
1835                 {
1836                     ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME;
1837                 }
1838
1839                 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1840                                                 NULL,
1841                                                 ulFilter,
1842                                                 FILE_ACTION_REMOVED);
1843
1844                 break;
1845             }
1846
1847             case AFS_INVALIDATE_FLUSHED:
1848             {
1849
1850                 if( pObjectInfo->FileType == AFS_FILE_TYPE_FILE &&
1851                     pObjectInfo->Fcb != NULL)
1852                 {
1853
1854                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1855                                   AFS_TRACE_LEVEL_VERBOSE,
1856                                   "AFSInvalidateCache Flush/purge file fid %08lX-%08lX-%08lX-%08lX\n",
1857                                   pObjectInfo->FileId.Cell,
1858                                   pObjectInfo->FileId.Volume,
1859                                   pObjectInfo->FileId.Vnode,
1860                                   pObjectInfo->FileId.Unique);
1861
1862                     AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource,
1863                                     TRUE);
1864
1865                     __try
1866                     {
1867
1868                         CcFlushCache( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers,
1869                                       NULL,
1870                                       0,
1871                                       &stIoStatus);
1872
1873                         if( !NT_SUCCESS( stIoStatus.Status))
1874                         {
1875
1876                             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1877                                           AFS_TRACE_LEVEL_ERROR,
1878                                           "AFSInvalidateCache CcFlushCache failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1879                                           pObjectInfo->FileId.Cell,
1880                                           pObjectInfo->FileId.Volume,
1881                                           pObjectInfo->FileId.Vnode,
1882                                           pObjectInfo->FileId.Unique,
1883                                           stIoStatus.Status,
1884                                           stIoStatus.Information);
1885
1886                             ntStatus = stIoStatus.Status;
1887                         }
1888
1889                         CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers,
1890                                              NULL,
1891                                              0,
1892                                              FALSE);
1893                     }
1894                     __except( EXCEPTION_EXECUTE_HANDLER)
1895                     {
1896
1897                         ntStatus = GetExceptionCode();
1898                     }
1899
1900                     AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource);
1901
1902                     //
1903                     // Clear out the extents
1904                     // Get rid of them (note this involves waiting
1905                     // for any writes or reads to the cache to complete)
1906                     //
1907
1908                     (VOID) AFSTearDownFcbExtents( pObjectInfo->Fcb);
1909                 }
1910
1911                 // Fall through to the default processing
1912             }
1913
1914             default:
1915             {
1916
1917                 if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY)
1918                 {
1919                     ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME;
1920                 }
1921                 else
1922                 {
1923                     ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME;
1924                 }
1925
1926                 if( InvalidateCB->Reason == AFS_INVALIDATE_CREDS)
1927                 {
1928                     ulFilter |= FILE_NOTIFY_CHANGE_SECURITY;
1929                 }
1930
1931                 if( InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION)
1932                 {
1933                     ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
1934                 }
1935                 else
1936                 {
1937                     ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
1938                 }
1939
1940                 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1941                                                 NULL,
1942                                                 ulFilter,
1943                                                 FILE_ACTION_MODIFIED);
1944
1945                 //
1946                 // Indicate this node requires re-evaluation for the remaining reasons
1947                 //
1948
1949                 pObjectInfo->Expiration.QuadPart = 0;
1950
1951                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1952                               AFS_TRACE_LEVEL_VERBOSE,
1953                               "AFSInvalidateCache Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n",
1954                               pObjectInfo->FileId.Cell,
1955                               pObjectInfo->FileId.Volume,
1956                               pObjectInfo->FileId.Vnode,
1957                               pObjectInfo->FileId.Unique);
1958
1959                 SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1960
1961                 if( InvalidateCB->Reason == AFS_INVALIDATE_FLUSHED ||
1962                     InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION)
1963                 {
1964                     pObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1965
1966                     if( pObjectInfo->FileType == AFS_FILE_TYPE_FILE)
1967                     {
1968
1969                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1970                                       AFS_TRACE_LEVEL_VERBOSE,
1971                                       "AFSInvalidateCache Setting VERIFY_DATA flag on fid %08lX-%08lX-%08lX-%08lX\n",
1972                                       pObjectInfo->FileId.Cell,
1973                                       pObjectInfo->FileId.Volume,
1974                                       pObjectInfo->FileId.Vnode,
1975                                       pObjectInfo->FileId.Unique);
1976
1977                         SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA);
1978                     }
1979                 }
1980
1981                 break;
1982             }
1983         }
1984
1985 try_exit:
1986
1987         if( pObjectInfo != NULL)
1988         {
1989
1990             InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1991
1992             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1993                           AFS_TRACE_LEVEL_VERBOSE,
1994                           "AFSInvalidateCache Decrement count on object %08lX Cnt %d\n",
1995                           pObjectInfo,
1996                           pObjectInfo->ObjectReferenceCount);
1997         }
1998     }
1999
2000     return ntStatus;
2001 }
2002
2003 BOOLEAN
2004 AFSIsChildOfParent( IN AFSFcb *Dcb,
2005                     IN AFSFcb *Fcb)
2006 {
2007
2008     BOOLEAN bIsChild = FALSE;
2009     AFSFcb *pCurrentFcb = Fcb;
2010
2011     while( pCurrentFcb != NULL)
2012     {
2013
2014         if( pCurrentFcb->ObjectInformation->ParentObjectInformation == Dcb->ObjectInformation)
2015         {
2016
2017             bIsChild = TRUE;
2018
2019             break;
2020         }
2021
2022         pCurrentFcb = pCurrentFcb->ObjectInformation->ParentObjectInformation->Fcb;
2023     }
2024
2025     return bIsChild;
2026 }
2027
2028 inline
2029 ULONGLONG
2030 AFSCreateHighIndex( IN AFSFileID *FileID)
2031 {
2032
2033     ULONGLONG ullIndex = 0;
2034
2035     ullIndex = (((ULONGLONG)FileID->Cell << 32) | FileID->Volume);
2036
2037     return ullIndex;
2038 }
2039
2040 inline
2041 ULONGLONG
2042 AFSCreateLowIndex( IN AFSFileID *FileID)
2043 {
2044
2045     ULONGLONG ullIndex = 0;
2046
2047     ullIndex = (((ULONGLONG)FileID->Vnode << 32) | FileID->Unique);
2048
2049     return ullIndex;
2050 }
2051
2052 BOOLEAN
2053 AFSCheckAccess( IN ACCESS_MASK DesiredAccess,
2054                 IN ACCESS_MASK GrantedAccess,
2055                 IN BOOLEAN DirectoryEntry)
2056 {
2057
2058     BOOLEAN bAccessGranted = TRUE;
2059
2060     //
2061     // Check if we are asking for read/write and granted only read only
2062     // NOTE: There will be more checks here
2063     //
2064
2065     if( !AFSCheckForReadOnlyAccess( DesiredAccess,
2066                                     DirectoryEntry) &&
2067         AFSCheckForReadOnlyAccess( GrantedAccess,
2068                                    DirectoryEntry))
2069     {
2070
2071         bAccessGranted = FALSE;
2072     }
2073
2074     return bAccessGranted;
2075 }
2076
2077 NTSTATUS
2078 AFSGetDriverStatus( IN AFSDriverStatusRespCB *DriverStatus)
2079 {
2080
2081     NTSTATUS         ntStatus = STATUS_SUCCESS;
2082     AFSDeviceExt    *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2083
2084     //
2085     // Start with read
2086     //
2087
2088     DriverStatus->Status = AFS_DRIVER_STATUS_READY;
2089
2090     if( AFSGlobalRoot == NULL)
2091     {
2092
2093         //
2094         // We are not ready
2095         //
2096
2097         DriverStatus->Status = AFS_DRIVER_STATUS_NOT_READY;
2098     }
2099
2100     if( pControlDevExt->Specific.Control.CommServiceCB.IrpPoolControlFlag != POOL_ACTIVE)
2101     {
2102
2103         //
2104         // No service yet
2105         //
2106
2107         DriverStatus->Status = AFS_DRIVER_STATUS_NO_SERVICE;
2108     }
2109
2110     return ntStatus;
2111 }
2112
2113 NTSTATUS
2114 AFSSubstituteSysName( IN UNICODE_STRING *ComponentName,
2115                       IN UNICODE_STRING *SubstituteName,
2116                       IN ULONG StringIndex)
2117 {
2118
2119     NTSTATUS ntStatus = STATUS_SUCCESS;
2120     AFSDeviceExt    *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2121     AFSSysNameCB    *pSysName = NULL;
2122     ERESOURCE       *pSysNameLock = NULL;
2123     ULONG            ulIndex = 1;
2124     USHORT           usIndex = 0;
2125     UNICODE_STRING   uniSysName;
2126
2127     __Enter
2128     {
2129
2130 #if defined(_WIN64)
2131
2132         if( IoIs32bitProcess( NULL))
2133         {
2134
2135             pSysNameLock = &pControlDevExt->Specific.Control.SysName32ListLock;
2136
2137             pSysName = pControlDevExt->Specific.Control.SysName32ListHead;
2138         }
2139         else
2140         {
2141
2142             pSysNameLock = &pControlDevExt->Specific.Control.SysName64ListLock;
2143
2144             pSysName = pControlDevExt->Specific.Control.SysName64ListHead;
2145         }
2146 #else
2147
2148         pSysNameLock = &pControlDevExt->Specific.Control.SysName32ListLock;
2149
2150         pSysName = pControlDevExt->Specific.Control.SysName32ListHead;
2151
2152 #endif
2153
2154         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2155                       AFS_TRACE_LEVEL_VERBOSE,
2156                       "AFSSubstituteSysName Acquiring SysName lock %08lX SHARED %08lX\n",
2157                       pSysNameLock,
2158                       PsGetCurrentThread());
2159
2160         AFSAcquireShared( pSysNameLock,
2161                           TRUE);
2162
2163         //
2164         // Find where we are in the list
2165         //
2166
2167         while( pSysName != NULL &&
2168             ulIndex < StringIndex)
2169         {
2170
2171             pSysName = pSysName->fLink;
2172
2173             ulIndex++;
2174         }
2175
2176         if( pSysName == NULL)
2177         {
2178
2179             try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND);
2180         }
2181
2182         RtlInitUnicodeString( &uniSysName,
2183                               L"@SYS");
2184         //
2185         // If it is a full component of @SYS then just substitue the
2186         // name in
2187         //
2188
2189         if( RtlCompareUnicodeString( &uniSysName,
2190                                      ComponentName,
2191                                      TRUE) == 0)
2192         {
2193
2194             SubstituteName->Length = pSysName->SysName.Length;
2195             SubstituteName->MaximumLength = SubstituteName->Length;
2196
2197             SubstituteName->Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
2198                                                                         SubstituteName->Length,
2199                                                                         AFS_SUBST_BUFFER_TAG);
2200
2201             if( SubstituteName->Buffer == NULL)
2202             {
2203
2204                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2205             }
2206
2207             RtlCopyMemory( SubstituteName->Buffer,
2208                            pSysName->SysName.Buffer,
2209                            pSysName->SysName.Length);
2210         }
2211         else
2212         {
2213
2214             usIndex = 0;
2215
2216             while( ComponentName->Buffer[ usIndex] != L'@')
2217             {
2218
2219                 usIndex++;
2220             }
2221
2222             SubstituteName->Length = (usIndex * sizeof( WCHAR)) + pSysName->SysName.Length;
2223             SubstituteName->MaximumLength = SubstituteName->Length;
2224
2225             SubstituteName->Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
2226                                                                         SubstituteName->Length,
2227                                                                         AFS_SUBST_BUFFER_TAG);
2228
2229             if( SubstituteName->Buffer == NULL)
2230             {
2231
2232                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2233             }
2234
2235             RtlCopyMemory( SubstituteName->Buffer,
2236                            ComponentName->Buffer,
2237                            usIndex * sizeof( WCHAR));
2238
2239             RtlCopyMemory( &SubstituteName->Buffer[ usIndex],
2240                            pSysName->SysName.Buffer,
2241                            pSysName->SysName.Length);
2242         }
2243
2244 try_exit:
2245
2246         AFSReleaseResource( pSysNameLock);
2247     }
2248
2249     return ntStatus;
2250 }
2251
2252 NTSTATUS
2253 AFSSubstituteNameInPath( IN OUT UNICODE_STRING *FullPathName,
2254                          IN OUT UNICODE_STRING *ComponentName,
2255                          IN UNICODE_STRING *SubstituteName,
2256                          IN OUT UNICODE_STRING *RemainingPath,
2257                          IN BOOLEAN FreePathName)
2258 {
2259
2260     NTSTATUS ntStatus = STATUS_SUCCESS;
2261     UNICODE_STRING uniPathName;
2262     USHORT usPrefixNameLen = 0;
2263     SHORT  sNameLenDelta = 0;
2264
2265     __Enter
2266     {
2267
2268         //
2269         // If the passed in name can handle the additional length
2270         // then just moves things around
2271         //
2272
2273         sNameLenDelta = SubstituteName->Length - ComponentName->Length;
2274
2275         usPrefixNameLen = (USHORT)(ComponentName->Buffer - FullPathName->Buffer);
2276
2277         if( FullPathName->MaximumLength > FullPathName->Length + sNameLenDelta)
2278         {
2279
2280             if( FullPathName->Length > usPrefixNameLen + ComponentName->Length)
2281             {
2282
2283                 RtlMoveMemory( &FullPathName->Buffer[ ((usPrefixNameLen*sizeof( WCHAR) + SubstituteName->Length)/sizeof( WCHAR))],
2284                                &FullPathName->Buffer[ ((usPrefixNameLen*sizeof( WCHAR) + ComponentName->Length)/sizeof( WCHAR))],
2285                                FullPathName->Length - usPrefixNameLen*sizeof( WCHAR) - ComponentName->Length);
2286             }
2287
2288             RtlCopyMemory( &FullPathName->Buffer[ usPrefixNameLen],
2289                            SubstituteName->Buffer,
2290                            SubstituteName->Length);
2291
2292             FullPathName->Length += sNameLenDelta;
2293
2294             ComponentName->Length += sNameLenDelta;
2295
2296             ComponentName->MaximumLength = ComponentName->Length;
2297
2298             if ( RemainingPath->Buffer)
2299             {
2300
2301                 RemainingPath->Buffer += sNameLenDelta/sizeof( WCHAR);
2302             }
2303
2304             try_return( ntStatus);
2305         }
2306
2307         //
2308         // Need to re-allocate the buffer
2309         //
2310
2311         uniPathName.Length = FullPathName->Length -
2312                                          ComponentName->Length +
2313                                          SubstituteName->Length;
2314
2315         uniPathName.MaximumLength = FullPathName->MaximumLength + PAGE_SIZE;
2316
2317         uniPathName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
2318                                                                 uniPathName.MaximumLength,
2319                                                                 AFS_NAME_BUFFER_FOUR_TAG);
2320
2321         if( uniPathName.Buffer == NULL)
2322         {
2323
2324             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2325         }
2326
2327         usPrefixNameLen = (USHORT)(ComponentName->Buffer - FullPathName->Buffer);
2328
2329         usPrefixNameLen *= sizeof( WCHAR);
2330
2331         RtlZeroMemory( uniPathName.Buffer,
2332                        uniPathName.MaximumLength);
2333
2334         RtlCopyMemory( uniPathName.Buffer,
2335                        FullPathName->Buffer,
2336                        usPrefixNameLen);
2337
2338         RtlCopyMemory( &uniPathName.Buffer[ (usPrefixNameLen/sizeof( WCHAR))],
2339                        SubstituteName->Buffer,
2340                        SubstituteName->Length);
2341
2342         if( FullPathName->Length > usPrefixNameLen + ComponentName->Length)
2343         {
2344
2345             RtlCopyMemory( &uniPathName.Buffer[ (usPrefixNameLen + SubstituteName->Length)/sizeof( WCHAR)],
2346                            &FullPathName->Buffer[ (usPrefixNameLen + ComponentName->Length)/sizeof( WCHAR)],
2347                            FullPathName->Length - usPrefixNameLen - ComponentName->Length);
2348         }
2349
2350         ComponentName->Buffer = uniPathName.Buffer + (ComponentName->Buffer - FullPathName->Buffer);
2351
2352         ComponentName->Length += sNameLenDelta;
2353
2354         ComponentName->MaximumLength = ComponentName->Length;
2355
2356         if ( RemainingPath->Buffer)
2357         {
2358
2359             RemainingPath->Buffer = uniPathName.Buffer
2360                 + (RemainingPath->Buffer - FullPathName->Buffer)
2361                 + sNameLenDelta/sizeof( WCHAR);
2362         }
2363
2364         if( FreePathName)
2365         {
2366             AFSExFreePool( FullPathName->Buffer);
2367         }
2368
2369         *FullPathName = uniPathName;
2370
2371 try_exit:
2372
2373         NOTHING;
2374     }
2375
2376     return ntStatus;
2377 }
2378
2379 NTSTATUS
2380 AFSInvalidateVolume( IN AFSVolumeCB *VolumeCB,
2381                      IN ULONG Reason)
2382 {
2383
2384     NTSTATUS ntStatus = STATUS_SUCCESS;
2385     AFSFcb *pFcb = NULL;
2386     AFSObjectInfoCB *pCurrentObject = NULL;
2387     ULONG ulFilter = 0;
2388
2389     __Enter
2390     {
2391
2392         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2393                       AFS_TRACE_LEVEL_VERBOSE,
2394                       "AFSInvalidateVolume Invalidate volume fid %08lX-%08lX-%08lX-%08lX Reason %08lX\n",
2395                       VolumeCB->ObjectInformation.FileId.Cell,
2396                       VolumeCB->ObjectInformation.FileId.Volume,
2397                       VolumeCB->ObjectInformation.FileId.Vnode,
2398                       VolumeCB->ObjectInformation.FileId.Unique,
2399                       Reason);
2400
2401         //
2402         // Depending on the reason for invalidation then perform work on the node
2403         //
2404
2405         switch( Reason)
2406         {
2407
2408             case AFS_INVALIDATE_DELETED:
2409             {
2410
2411                 //
2412                 // Mark this volume as invalid
2413                 //
2414
2415                 VolumeCB->ObjectInformation.Expiration.QuadPart = 0;
2416
2417                 SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID);
2418
2419                 SetFlag( VolumeCB->Flags, AFS_VOLUME_FLAGS_OFFLINE);
2420
2421                 AFSFsRtlNotifyFullReportChange( &VolumeCB->ObjectInformation,
2422                                                 NULL,
2423                                                 FILE_NOTIFY_CHANGE_DIR_NAME,
2424                                                 FILE_ACTION_REMOVED);
2425
2426                 AFSAcquireShared( VolumeCB->ObjectInfoTree.TreeLock,
2427                                   TRUE);
2428
2429                 pCurrentObject = VolumeCB->ObjectInfoListHead;
2430
2431                 while( pCurrentObject != NULL)
2432                 {
2433
2434                     if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY)
2435                     {
2436                         ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME;
2437                     }
2438                     else
2439                     {
2440                         ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME;
2441                     }
2442
2443                     AFSFsRtlNotifyFullReportChange( pCurrentObject,
2444                                                     NULL,
2445                                                     ulFilter,
2446                                                     FILE_ACTION_REMOVED);
2447
2448                     SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID);
2449
2450                     pFcb = pCurrentObject->Fcb;
2451
2452                     if( pFcb != NULL &&
2453                         pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
2454                     {
2455
2456
2457                         //
2458                         // Clear out the extents
2459                         // And get rid of them (note this involves waiting
2460                         // for any writes or reads to the cache to complete)
2461                         //
2462
2463                         (VOID) AFSTearDownFcbExtents( pFcb);
2464                     }
2465
2466                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2467                 }
2468
2469                 AFSReleaseResource( VolumeCB->ObjectInfoTree.TreeLock);
2470
2471                 break;
2472             }
2473
2474             default:
2475             {
2476
2477                 //
2478                 // Indicate this node requires re-evaluation for the remaining reasons
2479                 //
2480
2481                 VolumeCB->ObjectInformation.Expiration.QuadPart = 0;
2482
2483                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2484                               AFS_TRACE_LEVEL_VERBOSE,
2485                               "AFSInvalidateVolume Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n",
2486                               VolumeCB->ObjectInformation.FileId.Cell,
2487                               VolumeCB->ObjectInformation.FileId.Volume,
2488                               VolumeCB->ObjectInformation.FileId.Vnode,
2489                               VolumeCB->ObjectInformation.FileId.Unique);
2490
2491                 SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_VERIFY);
2492
2493                 if( Reason == AFS_INVALIDATE_FLUSHED ||
2494                     Reason == AFS_INVALIDATE_DATA_VERSION)
2495                 {
2496
2497                     VolumeCB->ObjectInformation.DataVersion.QuadPart = (ULONGLONG)-1;
2498                 }
2499
2500                 //
2501                 // Notify anyone that cares
2502                 //
2503
2504                 ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME;
2505
2506                 if( Reason == AFS_INVALIDATE_CREDS)
2507                 {
2508                     ulFilter |= FILE_NOTIFY_CHANGE_SECURITY;
2509                 }
2510
2511                 if( Reason == AFS_INVALIDATE_DATA_VERSION)
2512                 {
2513                     ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
2514                 }
2515                 else
2516                 {
2517                     ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
2518                 }
2519
2520                 AFSFsRtlNotifyFullReportChange( &VolumeCB->ObjectInformation,
2521                                                 NULL,
2522                                                 ulFilter,
2523                                                 FILE_ACTION_MODIFIED);
2524
2525                 //
2526                 // Volume invalidations require all objects in the volume be re-verified
2527                 //
2528
2529                 AFSAcquireShared( VolumeCB->ObjectInfoTree.TreeLock,
2530                                   TRUE);
2531
2532                 pCurrentObject = VolumeCB->ObjectInfoListHead;
2533
2534                 while( pCurrentObject != NULL)
2535                 {
2536
2537                     pCurrentObject->Expiration.QuadPart = 0;
2538
2539                     pCurrentObject->TargetFileId.Vnode = 0;
2540
2541                     pCurrentObject->TargetFileId.Unique = 0;
2542
2543                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2544                                   AFS_TRACE_LEVEL_VERBOSE,
2545                                   "AFSInvalidateVolume Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n",
2546                                   pCurrentObject->FileId.Cell,
2547                                   pCurrentObject->FileId.Volume,
2548                                   pCurrentObject->FileId.Vnode,
2549                                   pCurrentObject->FileId.Unique);
2550
2551                     SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY);
2552
2553                     if( Reason == AFS_INVALIDATE_FLUSHED ||
2554                         Reason == AFS_INVALIDATE_DATA_VERSION)
2555                     {
2556
2557                         pCurrentObject->DataVersion.QuadPart = (ULONGLONG)-1;
2558
2559                         if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE)
2560                         {
2561
2562                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2563                                           AFS_TRACE_LEVEL_VERBOSE,
2564                                           "AFSInvalidateVolume Setting VERIFY_DATA flag on fid %08lX-%08lX-%08lX-%08lX\n",
2565                                           pCurrentObject->FileId.Cell,
2566                                           pCurrentObject->FileId.Volume,
2567                                           pCurrentObject->FileId.Vnode,
2568                                           pCurrentObject->FileId.Unique);
2569
2570                             SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA);
2571                         }
2572                     }
2573
2574                     if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY)
2575                     {
2576                         ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME;
2577                     }
2578                     else
2579                     {
2580                         ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME;
2581                     }
2582
2583                     if( Reason == AFS_INVALIDATE_CREDS)
2584                     {
2585                         ulFilter |= FILE_NOTIFY_CHANGE_SECURITY;
2586                     }
2587
2588                     if( Reason == AFS_INVALIDATE_DATA_VERSION)
2589                     {
2590                         ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
2591                     }
2592                     else
2593                     {
2594                         ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
2595                     }
2596
2597                     AFSFsRtlNotifyFullReportChange( pCurrentObject,
2598                                                     NULL,
2599                                                     ulFilter,
2600                                                     FILE_ACTION_MODIFIED);
2601
2602                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2603                 }
2604
2605                 AFSReleaseResource( VolumeCB->ObjectInfoTree.TreeLock);
2606
2607                 break;
2608             }
2609         }
2610     }
2611
2612     return ntStatus;
2613 }
2614
2615 NTSTATUS
2616 AFSVerifyEntry( IN GUID *AuthGroup,
2617                 IN AFSDirectoryCB *DirEntry)
2618 {
2619
2620     NTSTATUS ntStatus = STATUS_SUCCESS;
2621     AFSDirEnumEntry *pDirEnumEntry = NULL;
2622     AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation;
2623     IO_STATUS_BLOCK stIoStatus;
2624
2625     __Enter
2626     {
2627
2628         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2629                       AFS_TRACE_LEVEL_VERBOSE_2,
2630                       "AFSVerifyEntry Verifying entry %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2631                       &DirEntry->NameInformation.FileName,
2632                       pObjectInfo->FileId.Cell,
2633                       pObjectInfo->FileId.Volume,
2634                       pObjectInfo->FileId.Vnode,
2635                       pObjectInfo->FileId.Unique);
2636
2637         ntStatus = AFSEvaluateTargetByID( pObjectInfo,
2638                                           AuthGroup,
2639                                           FALSE,
2640                                           &pDirEnumEntry);
2641
2642         if( !NT_SUCCESS( ntStatus))
2643         {
2644
2645             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2646                           AFS_TRACE_LEVEL_ERROR,
2647                           "AFSValidateEntry Evaluate Target failed %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
2648                           &DirEntry->NameInformation.FileName,
2649                           pObjectInfo->FileId.Cell,
2650                           pObjectInfo->FileId.Volume,
2651                           pObjectInfo->FileId.Vnode,
2652                           pObjectInfo->FileId.Unique,
2653                           ntStatus);
2654
2655             try_return( ntStatus);
2656         }
2657
2658         //
2659         // Check the data version of the file
2660         //
2661
2662         if( pObjectInfo->DataVersion.QuadPart == pDirEnumEntry->DataVersion.QuadPart &&
2663             !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA))
2664         {
2665
2666             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2667                           AFS_TRACE_LEVEL_VERBOSE,
2668                           "AFSVerifyEntry No DV change %I64X for Fcb %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2669                           pObjectInfo->DataVersion.QuadPart,
2670                           &DirEntry->NameInformation.FileName,
2671                           pObjectInfo->FileId.Cell,
2672                           pObjectInfo->FileId.Volume,
2673                           pObjectInfo->FileId.Vnode,
2674                           pObjectInfo->FileId.Unique);
2675
2676             //
2677             // We are ok, just get out
2678             //
2679
2680             ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
2681
2682             try_return( ntStatus = STATUS_SUCCESS);
2683         }
2684
2685         //
2686         // New data version so we will need to process the node based on the type
2687         //
2688
2689         switch( pDirEnumEntry->FileType)
2690         {
2691
2692             case AFS_FILE_TYPE_MOUNTPOINT:
2693             {
2694
2695                 //
2696                 // For a mount point we need to ensure the target is the same
2697                 //
2698
2699                 if( !AFSIsEqualFID( &pObjectInfo->TargetFileId,
2700                                     &pDirEnumEntry->TargetFileId))
2701                 {
2702
2703                 }
2704
2705                 //
2706                 // Update the metadata for the entry
2707                 //
2708
2709                 ntStatus = AFSUpdateMetaData( DirEntry,
2710                                               pDirEnumEntry);
2711
2712                 if( NT_SUCCESS( ntStatus))
2713                 {
2714
2715                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
2716                 }
2717
2718                 break;
2719             }
2720
2721             case AFS_FILE_TYPE_SYMLINK:
2722             {
2723
2724                 ASSERT( pDirEnumEntry->TargetNameLength > 0);
2725
2726                 //
2727                 // Update the metadata for the entry
2728                 //
2729
2730                 ntStatus = AFSUpdateMetaData( DirEntry,
2731                                               pDirEnumEntry);
2732
2733                 if( NT_SUCCESS( ntStatus))
2734                 {
2735
2736                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
2737                 }
2738
2739                 break;
2740             }
2741
2742             case AFS_FILE_TYPE_FILE:
2743             {
2744                 FILE_OBJECT * pCCFileObject = NULL;
2745                 BOOLEAN bPurgeExtents = FALSE;
2746
2747                 if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA))
2748                 {
2749                     bPurgeExtents = TRUE;
2750
2751                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2752                                   AFS_TRACE_LEVEL_VERBOSE,
2753                                   "AFSVerifyEntry Clearing VERIFY_DATA flag %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2754                                   &DirEntry->NameInformation.FileName,
2755                                   pObjectInfo->FileId.Cell,
2756                                   pObjectInfo->FileId.Volume,
2757                                   pObjectInfo->FileId.Vnode,
2758                                   pObjectInfo->FileId.Unique);
2759
2760                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA);
2761                 }
2762
2763                 //
2764                 // Update the metadata for the entry
2765                 //
2766
2767                 ntStatus = AFSUpdateMetaData( DirEntry,
2768                                               pDirEnumEntry);
2769
2770                 if( !NT_SUCCESS( ntStatus))
2771                 {
2772
2773                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2774                                   AFS_TRACE_LEVEL_ERROR,
2775                                   "AFSInvalidateCache Meta Data Update failed %wZ FID %08lX-%08lX-%08lX-%08lX ntStatus %08lX\n",
2776                                   &DirEntry->NameInformation.FileName,
2777                                   pObjectInfo->FileId.Cell,
2778                                   pObjectInfo->FileId.Volume,
2779                                   pObjectInfo->FileId.Vnode,
2780                                   pObjectInfo->FileId.Unique,
2781                                   ntStatus);
2782
2783                     break;
2784                 }
2785
2786                 if( pObjectInfo->Fcb != NULL)
2787                 {
2788
2789                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2790                                   AFS_TRACE_LEVEL_VERBOSE,
2791                                   "AFSVerifyEntry Flush/purge entry %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2792                                   &DirEntry->NameInformation.FileName,
2793                                   pObjectInfo->FileId.Cell,
2794                                   pObjectInfo->FileId.Volume,
2795                                   pObjectInfo->FileId.Vnode,
2796                                   pObjectInfo->FileId.Unique);
2797
2798                     AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource,
2799                                     TRUE);
2800
2801                     __try
2802                     {
2803
2804                         CcFlushCache( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers,
2805                                       NULL,
2806                                       0,
2807                                       &stIoStatus);
2808
2809                         if( !NT_SUCCESS( stIoStatus.Status))
2810                         {
2811
2812                             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2813                                           AFS_TRACE_LEVEL_ERROR,
2814                                           "AFSVerifyEntry CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
2815                                           &DirEntry->NameInformation.FileName,
2816                                           pObjectInfo->FileId.Cell,
2817                                           pObjectInfo->FileId.Volume,
2818                                           pObjectInfo->FileId.Vnode,
2819                                           pObjectInfo->FileId.Unique,
2820                                           stIoStatus.Status,
2821                                           stIoStatus.Information);
2822
2823                             ntStatus = stIoStatus.Status;
2824                         }
2825
2826                         if ( bPurgeExtents)
2827                         {
2828
2829                             CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers,
2830                                                  NULL,
2831                                                  0,
2832                                                  FALSE);
2833                         }
2834                     }
2835                     __except( EXCEPTION_EXECUTE_HANDLER)
2836                     {
2837                         ntStatus = GetExceptionCode();
2838
2839                         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2840                                       AFS_TRACE_LEVEL_ERROR,
2841                                       "AFSVerifyEntry CcFlushCache or CcPurgeCacheSection Exception %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
2842                                       &DirEntry->NameInformation.FileName,
2843                                       pObjectInfo->FileId.Cell,
2844                                       pObjectInfo->FileId.Volume,
2845                                       pObjectInfo->FileId.Vnode,
2846                                       pObjectInfo->FileId.Unique,
2847                                       ntStatus);
2848                     }
2849
2850                     AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource);
2851
2852                     if ( bPurgeExtents)
2853                     {
2854                         AFSFlushExtents( pObjectInfo->Fcb);
2855                     }
2856
2857                     //
2858                     // Reacquire the Fcb to purge the cache
2859                     //
2860
2861                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2862                                   AFS_TRACE_LEVEL_VERBOSE,
2863                                   "AFSVerifyEntry Acquiring Fcb lock %08lX EXCL %08lX\n",
2864                                   &pObjectInfo->Fcb->NPFcb->Resource,
2865                                   PsGetCurrentThread());
2866
2867                     AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource,
2868                                     TRUE);
2869
2870                     //
2871                     // Update file sizes
2872                     //
2873
2874                     pObjectInfo->Fcb->Header.AllocationSize.QuadPart  = pObjectInfo->AllocationSize.QuadPart;
2875                     pObjectInfo->Fcb->Header.FileSize.QuadPart        = pObjectInfo->EndOfFile.QuadPart;
2876                     pObjectInfo->Fcb->Header.ValidDataLength.QuadPart = pObjectInfo->EndOfFile.QuadPart;
2877
2878                     pCCFileObject = CcGetFileObjectFromSectionPtrs( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers);
2879
2880                     if ( pCCFileObject != NULL)
2881                     {
2882                         CcSetFileSizes( pCCFileObject,
2883                                         (PCC_FILE_SIZES)&pObjectInfo->Fcb->Header.AllocationSize);
2884                     }
2885
2886                     AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource);
2887                 }
2888                 else
2889                 {
2890                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2891                                   AFS_TRACE_LEVEL_WARNING,
2892                                   "AFSValidateEntry Fcb NULL %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2893                                   &DirEntry->NameInformation.FileName,
2894                                   pObjectInfo->FileId.Cell,
2895                                   pObjectInfo->FileId.Volume,
2896                                   pObjectInfo->FileId.Vnode,
2897                                   pObjectInfo->FileId.Unique);
2898                 }
2899
2900                 ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
2901
2902                 break;
2903             }
2904
2905             case AFS_FILE_TYPE_DIRECTORY:
2906             {
2907
2908                 AFSFcb *pCurrentFcb = NULL;
2909                 AFSDirectoryCB *pCurrentDirEntry = NULL;
2910
2911                 //
2912                 // For a directory or root entry flush the content of
2913                 // the directory enumeration.
2914                 //
2915
2916                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED))
2917                 {
2918
2919                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2920                                   AFS_TRACE_LEVEL_VERBOSE_2,
2921                                   "AFSVerifyEntry Validating directory content for entry %wZ FID %08lX-%08lX-%08lX-%08lX\n",
2922                                   &DirEntry->NameInformation.FileName,
2923                                   pObjectInfo->FileId.Cell,
2924                                   pObjectInfo->FileId.Volume,
2925                                   pObjectInfo->FileId.Vnode,
2926                                   pObjectInfo->FileId.Unique);
2927
2928                     AFSAcquireExcl( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
2929                                     TRUE);
2930
2931                     AFSValidateDirectoryCache( pObjectInfo,
2932                                                AuthGroup);
2933
2934                     AFSReleaseResource( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
2935                 }
2936
2937                 //
2938                 // Update the metadata for the entry
2939                 //
2940
2941                 ntStatus = AFSUpdateMetaData( DirEntry,
2942                                               pDirEnumEntry);
2943
2944                 if( NT_SUCCESS( ntStatus))
2945                 {
2946
2947                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
2948                 }
2949
2950                 break;
2951             }
2952
2953             case AFS_FILE_TYPE_DFSLINK:
2954             {
2955
2956                 UNICODE_STRING uniTargetName;
2957
2958                 //
2959                 // For a DFS link need to check the target name has not changed
2960                 //
2961
2962                 uniTargetName.Length = (USHORT)pDirEnumEntry->TargetNameLength;
2963
2964                 uniTargetName.MaximumLength = uniTargetName.Length;
2965
2966                 uniTargetName.Buffer = (WCHAR *)((char *)pDirEnumEntry + pDirEnumEntry->TargetNameOffset);
2967
2968                 AFSAcquireExcl( &DirEntry->NonPaged->Lock,
2969                                 TRUE);
2970
2971                 if( DirEntry->NameInformation.TargetName.Length == 0 ||
2972                     RtlCompareUnicodeString( &uniTargetName,
2973                                              &DirEntry->NameInformation.TargetName,
2974                                              TRUE) != 0)
2975                 {
2976
2977                     //
2978                     // Update the target name
2979                     //
2980
2981                     ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName,
2982                                                     &DirEntry->Flags,
2983                                                     uniTargetName.Buffer,
2984                                                     uniTargetName.Length);
2985
2986                     if( !NT_SUCCESS( ntStatus))
2987                     {
2988
2989                         AFSReleaseResource( &DirEntry->NonPaged->Lock);
2990
2991                         break;
2992                     }
2993                 }
2994
2995                 AFSReleaseResource( &DirEntry->NonPaged->Lock);
2996
2997                 //
2998                 // Update the metadata for the entry
2999                 //
3000
3001                 ntStatus = AFSUpdateMetaData( DirEntry,
3002                                               pDirEnumEntry);
3003
3004                 if( NT_SUCCESS( ntStatus))
3005                 {
3006
3007                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
3008                 }
3009
3010                 break;
3011             }
3012
3013             default:
3014
3015                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3016                               AFS_TRACE_LEVEL_WARNING,
3017                               "AFSVerifyEntry Attempt to verify node of type %d\n",
3018                               pObjectInfo->FileType);
3019
3020                 break;
3021         }
3022
3023  try_exit:
3024
3025         if( pDirEnumEntry != NULL)
3026         {
3027
3028             AFSExFreePool( pDirEnumEntry);
3029         }
3030     }
3031
3032     return ntStatus;
3033 }
3034
3035 NTSTATUS
3036 AFSSetVolumeState( IN AFSVolumeStatusCB *VolumeStatus)
3037 {
3038
3039     NTSTATUS ntStatus = STATUS_SUCCESS;
3040     AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
3041     ULONGLONG   ullIndex = 0;
3042     AFSVolumeCB *pVolumeCB = NULL;
3043     AFSFcb *pFcb = NULL;
3044     AFSObjectInfoCB *pCurrentObject = NULL;
3045
3046     __Enter
3047     {
3048
3049         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3050                       AFS_TRACE_LEVEL_VERBOSE,
3051                       "AFSSetVolumeState Marking volume state %d Volume Cell %08lX Volume %08lX\n",
3052                       VolumeStatus->Online,
3053                       VolumeStatus->FileID.Cell,
3054                       VolumeStatus->FileID.Volume);
3055
3056         //
3057         // Need to locate the Fcb for the directory to purge
3058         //
3059
3060         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3061                       AFS_TRACE_LEVEL_VERBOSE,
3062                       "AFSSetVolumeState Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
3063                       &pDevExt->Specific.RDR.VolumeTreeLock,
3064                       PsGetCurrentThread());
3065
3066         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
3067
3068         //
3069         // Locate the volume node
3070         //
3071
3072         ullIndex = AFSCreateHighIndex( &VolumeStatus->FileID);
3073
3074         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
3075                                        ullIndex,
3076                                        (AFSBTreeEntry **)&pVolumeCB);
3077
3078         if( pVolumeCB != NULL)
3079         {
3080
3081             InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
3082
3083             AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
3084
3085             //
3086             // Set the volume state accordingly
3087             //
3088
3089             if( VolumeStatus->Online)
3090             {
3091
3092                 InterlockedAnd( (LONG *)&(pVolumeCB->Flags), ~AFS_VOLUME_FLAGS_OFFLINE);
3093             }
3094             else
3095             {
3096
3097                 InterlockedOr( (LONG *)&(pVolumeCB->Flags), AFS_VOLUME_FLAGS_OFFLINE);
3098             }
3099
3100             AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
3101                               TRUE);
3102
3103             pCurrentObject = pVolumeCB->ObjectInfoListHead;;
3104
3105             while( pCurrentObject != NULL)
3106             {
3107
3108                 if( VolumeStatus->Online)
3109                 {
3110
3111                     ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID);
3112
3113                     SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY);
3114
3115                     pCurrentObject->DataVersion.QuadPart = (ULONGLONG)-1;
3116                 }
3117                 else
3118                 {
3119
3120                     SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID);
3121                 }
3122
3123                 pFcb = pCurrentObject->Fcb;
3124
3125                 if( pFcb != NULL &&
3126                     !(VolumeStatus->Online) &&
3127                     pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
3128                 {
3129
3130                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3131                                   AFS_TRACE_LEVEL_ERROR,
3132                                   "AFSSetVolumeState Marking volume offline and canceling extents Volume Cell %08lX Volume %08lX\n",
3133                                   VolumeStatus->FileID.Cell,
3134                                   VolumeStatus->FileID.Volume);
3135
3136                     //
3137                     // Clear out the extents
3138                     //
3139
3140                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3141                                   AFS_TRACE_LEVEL_VERBOSE,
3142                                   "AFSSetVolumeState Acquiring Fcb extents lock %08lX EXCL %08lX\n",
3143                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
3144                                   PsGetCurrentThread());
3145
3146                     AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
3147                                     TRUE);
3148
3149                     pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
3150
3151                     KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
3152                                 0,
3153                                 FALSE);
3154
3155                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3156                                   AFS_TRACE_LEVEL_VERBOSE,
3157                                   "AFSSetVolumeState Releasing Fcb extents lock %08lX EXCL %08lX\n",
3158                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
3159                                   PsGetCurrentThread());
3160
3161                     AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
3162
3163                     //
3164                     // And get rid of them (note this involves waiting
3165                     // for any writes or reads to the cache to complete)
3166                     //
3167
3168                     (VOID) AFSTearDownFcbExtents( pFcb);
3169                 }
3170
3171                 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
3172             }
3173
3174             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
3175
3176             InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
3177         }
3178         else
3179         {
3180
3181             AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
3182         }
3183     }
3184
3185     return ntStatus;
3186 }
3187
3188 NTSTATUS
3189 AFSSetNetworkState( IN AFSNetworkStatusCB *NetworkStatus)
3190 {
3191
3192     NTSTATUS ntStatus = STATUS_SUCCESS;
3193
3194     __Enter
3195     {
3196
3197         if( AFSGlobalRoot == NULL)
3198         {
3199
3200             try_return( ntStatus);
3201         }
3202
3203         AFSAcquireExcl( AFSGlobalRoot->VolumeLock,
3204                         TRUE);
3205
3206         //
3207         // Set the network state according to the information
3208         //
3209
3210         if( NetworkStatus->Online)
3211         {
3212
3213             ClearFlag( AFSGlobalRoot->Flags, AFS_VOLUME_FLAGS_OFFLINE);
3214         }
3215         else
3216         {
3217
3218             SetFlag( AFSGlobalRoot->Flags, AFS_VOLUME_FLAGS_OFFLINE);
3219         }
3220
3221         AFSReleaseResource( AFSGlobalRoot->VolumeLock);
3222
3223 try_exit:
3224
3225         NOTHING;
3226     }
3227
3228     return ntStatus;
3229 }
3230
3231 NTSTATUS
3232 AFSValidateDirectoryCache( IN AFSObjectInfoCB *ObjectInfo,
3233                            IN GUID *AuthGroup)
3234 {
3235
3236     NTSTATUS ntStatus = STATUS_SUCCESS;
3237     BOOLEAN  bAcquiredLock = FALSE;
3238     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
3239     AFSFcb *pFcb = NULL;
3240
3241     __Enter
3242     {
3243
3244         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3245                       AFS_TRACE_LEVEL_VERBOSE,
3246                       "AFSValidateDirectoryCache Validating content for FID %08lX-%08lX-%08lX-%08lX\n",
3247                       ObjectInfo->FileId.Cell,
3248                       ObjectInfo->FileId.Volume,
3249                       ObjectInfo->FileId.Vnode,
3250                       ObjectInfo->FileId.Unique);
3251
3252         if( !ExIsResourceAcquiredLite( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock))
3253         {
3254
3255             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3256                           AFS_TRACE_LEVEL_VERBOSE,
3257                           "AFSValidateDirectoryCache Acquiring DirectoryNodeHdr.TreeLock lock %08lX EXCL %08lX\n",
3258                           ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
3259                           PsGetCurrentThread());
3260
3261             AFSAcquireExcl( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
3262                             TRUE);
3263
3264             bAcquiredLock = TRUE;
3265         }
3266
3267         //
3268         // Check for inconsistency between DirectoryNodeList and DirectoryNodeCount
3269         //
3270
3271         if ( ObjectInfo->Specific.Directory.DirectoryNodeListHead == NULL &&
3272              ObjectInfo->Specific.Directory.DirectoryNodeCount > 0)
3273         {
3274
3275             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3276                           AFS_TRACE_LEVEL_ERROR,
3277                           "AFSValidateDirectoryCache Empty Node List but Non-Zero Node Count %08lX for dir FID %08lX-%08lX-%08lX-%08lX\n",
3278                           ObjectInfo->Specific.Directory.DirectoryNodeCount,
3279                           ObjectInfo->FileId.Cell,
3280                           ObjectInfo->FileId.Volume,
3281                           ObjectInfo->FileId.Vnode,
3282                           ObjectInfo->FileId.Unique);
3283         }
3284
3285         //
3286         // Reset the directory list information by clearing all valid entries
3287         //
3288
3289         pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead;
3290
3291         while( pCurrentDirEntry != NULL)
3292         {
3293
3294             if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
3295             {
3296
3297                 ClearFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID);
3298             }
3299
3300             pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
3301         }
3302
3303         //
3304         // Reget the directory contents
3305         //
3306
3307         AFSVerifyDirectoryContent( ObjectInfo,
3308                                    AuthGroup);
3309
3310         //
3311         // Now start again and tear down any entries not valid
3312         //
3313
3314         pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead;
3315
3316         while( pCurrentDirEntry != NULL)
3317         {
3318
3319             pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
3320
3321             if( BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID))
3322             {
3323
3324                 pCurrentDirEntry = pNextDirEntry;
3325
3326                 continue;
3327             }
3328
3329             if( pCurrentDirEntry->OpenReferenceCount == 0)
3330             {
3331
3332                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3333                               AFS_TRACE_LEVEL_VERBOSE,
3334                               "AFSValidateDirectoryCache Deleting dir entry %wZ from parent FID %08lX-%08lX-%08lX-%08lX\n",
3335                               &pCurrentDirEntry->NameInformation.FileName,
3336                               ObjectInfo->FileId.Cell,
3337                               ObjectInfo->FileId.Volume,
3338                               ObjectInfo->FileId.Vnode,
3339                               ObjectInfo->FileId.Unique);
3340
3341                 AFSDeleteDirEntry( ObjectInfo,
3342                                    pCurrentDirEntry);
3343             }
3344             else
3345             {
3346
3347                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3348                               AFS_TRACE_LEVEL_VERBOSE,
3349                               "AFSValidateDirectoryCache Setting dir entry %p Name %wZ DELETED in parent FID %08lX-%08lX-%08lX-%08lX\n",
3350                               pCurrentDirEntry,
3351                               &pCurrentDirEntry->NameInformation.FileName,
3352                               ObjectInfo->FileId.Cell,
3353                               ObjectInfo->FileId.Volume,
3354                               ObjectInfo->FileId.Vnode,
3355                               ObjectInfo->FileId.Unique);
3356
3357                 SetFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_DELETED);
3358
3359                 AFSRemoveNameEntry( ObjectInfo,
3360                                     pCurrentDirEntry);
3361             }
3362
3363             pCurrentDirEntry = pNextDirEntry;
3364         }
3365
3366 #if DBG
3367         if( !AFSValidateDirList( ObjectInfo))
3368         {
3369
3370             AFSPrint("AFSValidateDirectoryCache Invalid count ...\n");
3371         }
3372 #endif
3373
3374         if( bAcquiredLock)
3375         {
3376
3377             AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
3378         }
3379     }
3380
3381     return ntStatus;
3382 }
3383
3384 BOOLEAN
3385 AFSIsVolumeFID( IN AFSFileID *FileID)
3386 {
3387
3388     BOOLEAN bIsVolume = FALSE;
3389
3390     if( FileID->Vnode == 1 &&
3391         FileID->Unique == 1)
3392     {
3393
3394         bIsVolume = TRUE;
3395     }
3396
3397     return bIsVolume;
3398 }
3399
3400 BOOLEAN
3401 AFSIsFinalNode( IN AFSFcb *Fcb)
3402 {
3403
3404     BOOLEAN bIsFinalNode = FALSE;
3405
3406     if( Fcb->Header.NodeTypeCode == AFS_ROOT_FCB ||
3407         Fcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB ||
3408         Fcb->Header.NodeTypeCode == AFS_FILE_FCB ||
3409         Fcb->Header.NodeTypeCode == AFS_DFS_LINK_FCB ||
3410         Fcb->Header.NodeTypeCode == AFS_INVALID_FCB )
3411     {
3412
3413         bIsFinalNode = TRUE;
3414     }
3415     else
3416     {
3417
3418         ASSERT( Fcb->Header.NodeTypeCode == AFS_MOUNT_POINT_FCB ||
3419                 Fcb->Header.NodeTypeCode == AFS_SYMBOLIC_LINK_FCB);
3420     }
3421
3422     return bIsFinalNode;
3423 }
3424
3425 NTSTATUS
3426 AFSUpdateMetaData( IN AFSDirectoryCB *DirEntry,
3427                    IN AFSDirEnumEntry *DirEnumEntry)
3428 {
3429
3430     NTSTATUS ntStatus = STATUS_SUCCESS;
3431     UNICODE_STRING uniTargetName;
3432     AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation;
3433
3434     __Enter
3435     {
3436
3437         pObjectInfo->TargetFileId = DirEnumEntry->TargetFileId;
3438
3439         pObjectInfo->Expiration = DirEnumEntry->Expiration;
3440
3441         pObjectInfo->DataVersion = DirEnumEntry->DataVersion;
3442
3443         pObjectInfo->FileType = DirEnumEntry->FileType;
3444
3445         pObjectInfo->CreationTime = DirEnumEntry->CreationTime;
3446
3447         pObjectInfo->LastAccessTime = DirEnumEntry->LastAccessTime;
3448
3449         pObjectInfo->LastWriteTime = DirEnumEntry->LastWriteTime;
3450
3451         pObjectInfo->ChangeTime = DirEnumEntry->ChangeTime;
3452
3453         pObjectInfo->EndOfFile = DirEnumEntry->EndOfFile;
3454
3455         pObjectInfo->AllocationSize = DirEnumEntry->AllocationSize;
3456
3457         pObjectInfo->FileAttributes = DirEnumEntry->FileAttributes;
3458
3459         if( pObjectInfo->FileType == AFS_FILE_TYPE_MOUNTPOINT ||
3460             pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK ||
3461             pObjectInfo->FileType == AFS_FILE_TYPE_DFSLINK)
3462         {
3463
3464             pObjectInfo->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
3465         }
3466
3467         pObjectInfo->EaSize = DirEnumEntry->EaSize;
3468
3469         pObjectInfo->Links = DirEnumEntry->Links;
3470
3471         if( DirEnumEntry->TargetNameLength > 0)
3472         {
3473
3474             //
3475             // Update the target name information if needed
3476             //
3477
3478             uniTargetName.Length = (USHORT)DirEnumEntry->TargetNameLength;
3479
3480             uniTargetName.MaximumLength = uniTargetName.Length;
3481
3482             uniTargetName.Buffer = (WCHAR *)((char *)DirEnumEntry + DirEnumEntry->TargetNameOffset);
3483
3484             AFSAcquireExcl( &DirEntry->NonPaged->Lock,
3485                             TRUE);
3486
3487             if( DirEntry->NameInformation.TargetName.Length == 0 ||
3488                 RtlCompareUnicodeString( &uniTargetName,
3489                                          &DirEntry->NameInformation.TargetName,
3490                                          TRUE) != 0)
3491             {
3492
3493                 //
3494                 // Update the target name
3495                 //
3496
3497                 ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName,
3498                                                 &DirEntry->Flags,
3499                                                 uniTargetName.Buffer,
3500                                                 uniTargetName.Length);
3501
3502                 if( !NT_SUCCESS( ntStatus))
3503                 {
3504
3505                     AFSReleaseResource( &DirEntry->NonPaged->Lock);
3506
3507                     try_return( ntStatus);
3508                 }
3509             }
3510
3511             AFSReleaseResource( &DirEntry->NonPaged->Lock);
3512         }
3513         else if( DirEntry->NameInformation.TargetName.Length > 0)
3514         {
3515
3516             AFSAcquireExcl( &DirEntry->NonPaged->Lock,
3517                             TRUE);
3518
3519             if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER) &&
3520                 DirEntry->NameInformation.TargetName.Buffer != NULL)
3521             {
3522                 AFSExFreePool( DirEntry->NameInformation.TargetName.Buffer);
3523             }
3524
3525             ClearFlag( DirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER);
3526
3527             DirEntry->NameInformation.TargetName.Length = 0;
3528             DirEntry->NameInformation.TargetName.MaximumLength = 0;
3529             DirEntry->NameInformation.TargetName.Buffer = NULL;
3530
3531             AFSReleaseResource( &DirEntry->NonPaged->Lock);
3532         }
3533
3534 try_exit:
3535
3536         NOTHING;
3537     }
3538
3539     return ntStatus;
3540 }
3541
3542 NTSTATUS
3543 AFSValidateEntry( IN AFSDirectoryCB *DirEntry,
3544                   IN GUID *AuthGroup,
3545                   IN BOOLEAN PurgeContent,
3546                   IN BOOLEAN FastCall)
3547 {
3548
3549     NTSTATUS ntStatus = STATUS_SUCCESS;
3550     LARGE_INTEGER liSystemTime;
3551     AFSDirEnumEntry *pDirEnumEntry = NULL;
3552     AFSFcb *pCurrentFcb = NULL;
3553     BOOLEAN bReleaseFcb = FALSE;
3554     AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation;
3555
3556     __Enter
3557     {
3558
3559         //
3560         // If we have an Fcb hanging off the directory entry then be sure to acquire the locks in the
3561         // correct order
3562         //
3563
3564         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3565                       AFS_TRACE_LEVEL_VERBOSE_2,
3566                       "AFSValidateEntry Validating entry %wZ FID %08lX-%08lX-%08lX-%08lX\n",
3567                       &DirEntry->NameInformation.FileName,
3568                       pObjectInfo->FileId.Cell,
3569                       pObjectInfo->FileId.Volume,
3570                       pObjectInfo->FileId.Vnode,
3571                       pObjectInfo->FileId.Unique);
3572
3573         //
3574         // If this is a fake node then bail since the service knows nothing about it
3575         //
3576
3577         if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_FAKE))
3578         {
3579
3580             try_return( ntStatus);
3581         }
3582
3583         if( PurgeContent &&
3584             pObjectInfo->Fcb != NULL)
3585         {
3586
3587             pCurrentFcb = pObjectInfo->Fcb;
3588
3589             if( !ExIsResourceAcquiredLite( &pCurrentFcb->NPFcb->Resource))
3590             {
3591
3592                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3593                               AFS_TRACE_LEVEL_VERBOSE,
3594                               "AFSValidateEntry Acquiring Fcb lock %08lX EXCL %08lX\n",
3595                               &pCurrentFcb->NPFcb->Resource,
3596                               PsGetCurrentThread());
3597
3598                 AFSAcquireExcl( &pCurrentFcb->NPFcb->Resource,
3599                                 TRUE);
3600
3601                 bReleaseFcb = TRUE;
3602             }
3603         }
3604
3605         //
3606         // This routine ensures that the current entry is valid by:
3607         //
3608         //      1) Checking that the expiration time is non-zero and after where we
3609         //         currently are
3610         //
3611
3612         KeQuerySystemTime( &liSystemTime);
3613
3614         if( !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED) &&
3615             !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY) &&
3616             !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA) &&
3617             pObjectInfo->Expiration.QuadPart >= liSystemTime.QuadPart)
3618         {
3619
3620             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3621                           AFS_TRACE_LEVEL_VERBOSE_2,
3622                           "AFSValidateEntry Directory entry %wZ FID %08lX-%08lX-%08lX-%08lX VALID\n",
3623                           &DirEntry->NameInformation.FileName,
3624                           pObjectInfo->FileId.Cell,
3625                           pObjectInfo->FileId.Volume,
3626                           pObjectInfo->FileId.Vnode,
3627                           pObjectInfo->FileId.Unique);
3628
3629             try_return( ntStatus);
3630         }
3631
3632         //
3633         // This node requires updating
3634         //
3635
3636         ntStatus = AFSEvaluateTargetByID( pObjectInfo,
3637                                           AuthGroup,
3638                                           FastCall,
3639                                           &pDirEnumEntry);
3640
3641         if( !NT_SUCCESS( ntStatus))
3642         {
3643
3644             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3645                           AFS_TRACE_LEVEL_ERROR,
3646                           "AFSValidateEntry Failed to evaluate entry %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
3647                           &DirEntry->NameInformation.FileName,
3648                           pObjectInfo->FileId.Cell,
3649                           pObjectInfo->FileId.Volume,
3650                           pObjectInfo->FileId.Vnode,
3651                           pObjectInfo->FileId.Unique,
3652                           ntStatus);
3653
3654             //
3655             // Failed validation of node so return access-denied
3656             //
3657
3658             try_return( ntStatus);
3659         }
3660
3661         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3662                       AFS_TRACE_LEVEL_VERBOSE,
3663                       "AFSValidateEntry Validating entry %wZ FID %08lX-%08lX-%08lX-%08lX DV %I64X returned DV %I64X FT %d\n",
3664                       &DirEntry->NameInformation.FileName,
3665                       pObjectInfo->FileId.Cell,
3666                       pObjectInfo->FileId.Volume,
3667                       pObjectInfo->FileId.Vnode,
3668                       pObjectInfo->FileId.Unique,
3669                       pObjectInfo->DataVersion.QuadPart,
3670                       pDirEnumEntry->DataVersion.QuadPart,
3671                       pDirEnumEntry->FileType);
3672
3673
3674         //
3675         // Based on the file type, process the node
3676         //
3677
3678         switch( pDirEnumEntry->FileType)
3679         {
3680
3681             case AFS_FILE_TYPE_MOUNTPOINT:
3682             {
3683
3684                 //
3685                 // Update the metadata for the entry
3686                 //
3687
3688                 ntStatus = AFSUpdateMetaData( DirEntry,
3689                                               pDirEnumEntry);
3690
3691                 if( NT_SUCCESS( ntStatus))
3692                 {
3693
3694                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED);
3695                 }
3696
3697                 break;
3698             }
3699
3700             case AFS_FILE_TYPE_SYMLINK:
3701             case AFS_FILE_TYPE_DFSLINK:
3702             {
3703
3704                 //
3705                 // Update the metadata for the entry
3706                 //
3707
3708                 ntStatus = AFSUpdateMetaData( DirEntry,
3709                                               pDirEnumEntry);
3710
3711                 if( NT_SUCCESS( ntStatus))
3712                 {
3713
3714                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED);
3715                 }
3716
3717                 break;
3718             }
3719
3720             case AFS_FILE_TYPE_FILE:
3721             {
3722
3723                 //
3724                 // For a file where the data version has become invalid we need to
3725                 // fail any current extent requests and purge the cache for the file
3726                 // Can't hold the Fcb resource while doing this
3727                 //
3728
3729                 if( pCurrentFcb != NULL &&
3730                     (pObjectInfo->DataVersion.QuadPart != pDirEnumEntry->DataVersion.QuadPart ||
3731                     BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA)))
3732                 {
3733
3734                     IO_STATUS_BLOCK stIoStatus;
3735                     BOOLEAN bPurgeExtents = FALSE;
3736
3737                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3738                                   AFS_TRACE_LEVEL_VERBOSE_2,
3739                                   "AFSValidateEntry Flush/purge entry %wZ FID %08lX-%08lX-%08lX-%08lX\n",
3740                                   &DirEntry->NameInformation.FileName,
3741                                   pObjectInfo->FileId.Cell,
3742                                   pObjectInfo->FileId.Volume,
3743                                   pObjectInfo->FileId.Vnode,
3744                                   pObjectInfo->FileId.Unique);
3745
3746                     if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA))
3747                     {
3748                         bPurgeExtents = TRUE;
3749
3750                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
3751                                       AFS_TRACE_LEVEL_VERBOSE,
3752                                       "AFSVerifyEntry Clearing VERIFY_DATA flag %wZ FID %08lX-%08lX-%08lX-%08lX\n",
3753                           &nbs