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