Windows: File Attribute Reporting Consistency
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSCleanup.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: AFSCleanup.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSCleanup
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_CLEANUP dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
55             IN PIRP Irp)
56 {
57     UNREFERENCED_PARAMETER(LibDeviceObject);
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     AFSDeviceExt *pDeviceExt = NULL;
60     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
61     AFSFcb *pFcb = NULL;
62     AFSCcb *pCcb = NULL;
63     PFILE_OBJECT pFileObject = NULL;
64     AFSFcb *pRootFcb = NULL;
65     AFSDeviceExt *pControlDeviceExt = NULL;
66     IO_STATUS_BLOCK stIoSB;
67     AFSObjectInfoCB *pObjectInfo = NULL;
68     AFSObjectInfoCB *pParentObjectInfo = NULL;
69     AFSFileCleanupCB stFileCleanup;
70     AFSFileCleanupResultCB *pResultCB = NULL;
71     ULONG ulResultLen = 0;
72     ULONG   ulNotificationFlags = 0;
73     LONG    lCount;
74
75     __try
76     {
77
78         if( AFSRDRDeviceObject == NULL)
79         {
80
81             //
82             // Let this through, it's a cleanup on the library control device
83             //
84
85             try_return( ntStatus);
86         }
87
88         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
89
90         pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
91
92         //
93         // Set some initial variables to make processing easier
94         //
95
96         pFileObject = pIrpSp->FileObject;
97
98         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
99
100         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
101
102         if( pFcb == NULL)
103         {
104             try_return( ntStatus);
105         }
106
107         pObjectInfo = pFcb->ObjectInformation;
108
109         if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
110         {
111
112             pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
113                                                    &pObjectInfo->ParentFileId);
114         }
115
116         pRootFcb = pObjectInfo->VolumeCB->RootFcb;
117
118         RtlZeroMemory( &stFileCleanup,
119                        sizeof( AFSFileCleanupCB));
120
121         stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
122
123         stFileCleanup.Identifier = (ULONGLONG)pFileObject;
124
125         //
126         // Allocate our return buffer
127         //
128
129         pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
130                                                                         PAGE_SIZE,
131                                                                         AFS_GENERIC_MEMORY_32_TAG);
132
133         if( pResultCB == NULL)
134         {
135
136             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
137         }
138
139         RtlZeroMemory( pResultCB,
140                        PAGE_SIZE);
141
142         ulResultLen = PAGE_SIZE;
143
144
145         //
146         // Perform the cleanup functionality depending on the type of node it is
147         //
148
149         switch( pFcb->Header.NodeTypeCode)
150         {
151
152             case AFS_ROOT_ALL:
153             {
154
155                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
156                               AFS_TRACE_LEVEL_VERBOSE,
157                               "AFSCleanup Acquiring GlobalRoot lock %p EXCL %08lX\n",
158                               &pFcb->NPFcb->Resource,
159                               PsGetCurrentThread());
160
161                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
162                                   TRUE);
163
164                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
165                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
166                                     pCcb);
167
168                 ASSERT( pFcb->OpenHandleCount != 0);
169
170                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
171
172                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
173                               AFS_TRACE_LEVEL_VERBOSE,
174                               "AFSCleanup (RootAll) Decrement handle count on Fcb %p Cnt %d\n",
175                               pFcb,
176                               lCount);
177
178                 AFSReleaseResource( &pFcb->NPFcb->Resource);
179
180                 break;
181             }
182
183             case AFS_IOCTL_FCB:
184             {
185
186                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
187                               AFS_TRACE_LEVEL_VERBOSE,
188                               "AFSCleanup Acquiring PIOCtl lock %p EXCL %08lX\n",
189                               &pFcb->NPFcb->Resource,
190                               PsGetCurrentThread());
191
192                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
193                                   TRUE);
194
195                 ASSERT( pFcb->OpenHandleCount != 0);
196
197                 //
198                 // Decrement the open child handle count
199                 //
200
201                 if( pParentObjectInfo != NULL &&
202                     pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
203                 {
204
205                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
206
207                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
208                                   AFS_TRACE_LEVEL_VERBOSE,
209                                   "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %p Cnt %d\n",
210                                   pParentObjectInfo,
211                                   lCount);
212                 }
213
214                 AFSReleaseResource( &pFcb->NPFcb->Resource);
215
216                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
217
218                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
219                               AFS_TRACE_LEVEL_VERBOSE,
220                               "AFSCleanup (IOCtl) Decrement handle count on Fcb %p Cnt %d\n",
221                               pFcb,
222                               lCount);
223
224                 break;
225             }
226
227             //
228             // This Fcb represents a file
229             //
230
231             case AFS_FILE_FCB:
232             {
233
234                 //
235                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
236                 //
237
238                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
239                               AFS_TRACE_LEVEL_VERBOSE,
240                               "AFSCleanup Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
241                               &pFcb->NPFcb->SectionObjectResource,
242                               PsGetCurrentThread());
243
244                 AFSAcquireExcl( &pFcb->NPFcb->SectionObjectResource,
245                                 TRUE);
246
247                 //
248                 // If the handle has write permission ...
249                 //
250
251                 if( ((pCcb->GrantedAccess & FILE_WRITE_DATA) || pFcb->OpenHandleCount == 1) &&
252                     CcIsFileCached( pIrpSp->FileObject))
253                 {
254
255                     __try
256                     {
257
258                         CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
259                                       NULL,
260                                       0,
261                                       &stIoSB);
262
263                         if( !NT_SUCCESS( stIoSB.Status))
264                         {
265
266                             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
267                                           AFS_TRACE_LEVEL_ERROR,
268                                           "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
269                                           &pCcb->FullFileName,
270                                           pObjectInfo->FileId.Cell,
271                                           pObjectInfo->FileId.Volume,
272                                           pObjectInfo->FileId.Vnode,
273                                           pObjectInfo->FileId.Unique,
274                                           stIoSB.Status,
275                                           stIoSB.Information);
276
277                             ntStatus = stIoSB.Status;
278                         }
279
280                         if ( ( pFcb->OpenHandleCount == 1 ||
281                                BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE)) &&
282                              pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL)
283                         {
284
285                             if ( !CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers,
286                                                        NULL,
287                                                        0,
288                                                        FALSE))
289                             {
290
291                                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
292                                               AFS_TRACE_LEVEL_WARNING,
293                                               "AFSCleanup CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
294                                               pObjectInfo->FileId.Cell,
295                                               pObjectInfo->FileId.Volume,
296                                               pObjectInfo->FileId.Vnode,
297                                               pObjectInfo->FileId.Unique);
298
299                                 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
300                             }
301                             else
302                             {
303                                 ClearFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
304                             }
305                         }
306                     }
307                     __except( EXCEPTION_EXECUTE_HANDLER)
308                     {
309
310                         ntStatus = GetExceptionCode();
311
312                         AFSDbgLogMsg( 0,
313                                       0,
314                                       "EXCEPTION - AFSCleanup Cc FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
315                                       pObjectInfo->FileId.Cell,
316                                       pObjectInfo->FileId.Volume,
317                                       pObjectInfo->FileId.Vnode,
318                                       pObjectInfo->FileId.Unique,
319                                       ntStatus);
320
321                         SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
322                     }
323                 }
324
325                 //
326                 // Uninitialize the cache map. This call is unconditional.
327                 //
328
329                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
330                               AFS_TRACE_LEVEL_VERBOSE,
331                               "AFSCleanup Tearing down cache map for Fcb %p FileObject %p\n",
332                               pFcb,
333                               pFileObject);
334
335                 CcUninitializeCacheMap( pFileObject,
336                                         NULL,
337                                         NULL);
338
339
340                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
341                               AFS_TRACE_LEVEL_VERBOSE,
342                               "AFSCleanup Releasing Fcb SectionObject lock %p EXCL %08lX\n",
343                               &pFcb->NPFcb->SectionObjectResource,
344                               PsGetCurrentThread());
345
346                 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
347
348                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
349                               AFS_TRACE_LEVEL_VERBOSE,
350                               "AFSCleanup Acquiring Fcb lock %p EXCL %08lX\n",
351                               &pFcb->NPFcb->Resource,
352                               PsGetCurrentThread());
353
354                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
355                                 TRUE);
356
357                 //
358                 // Unlock all outstanding locks on the file, again, unconditionally
359                 //
360
361                 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
362                                            pFileObject,
363                                            IoGetRequestorProcess( Irp),
364                                            NULL);
365
366                 //
367                 // Tell the service to unlock all on the file
368                 //
369
370                 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
371
372                 //
373                 // Perform some final common processing
374                 //
375
376                 ASSERT( pFcb->OpenHandleCount != 0);
377
378                 if( pParentObjectInfo != NULL)
379                 {
380
381                     stFileCleanup.ParentId = pParentObjectInfo->FileId;
382                 }
383
384                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
385
386                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
387                 {
388
389                     stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
390
391                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
392
393                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
394                     {
395
396                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
397
398                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
399                     }
400
401                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
402                     {
403
404                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
405
406                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
407                     }
408
409                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
410                     {
411
412                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
413
414                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
415                     }
416
417                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
418                     {
419
420                         stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
421
422                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
423                     }
424                 }
425
426                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
427                 {
428
429                     stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
430                 }
431
432                 //
433                 // If the count has dropped to one and there is a pending delete
434                 // then delete the node.  The final count will be decremented just
435                 // before the Fcb->NPFcb->Resource is released.
436                 //
437
438                 if( pFcb->OpenHandleCount == 1 &&
439                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
440                 {
441
442                     ntStatus = STATUS_SUCCESS;
443
444                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
445
446                     //
447                     // Indicate the file access mode that is being released
448                     //
449
450                     stFileCleanup.FileAccess = pCcb->FileAccess;
451
452                     //
453                     // Push the request to the service
454                     //
455
456                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
457                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
458                                                   &pCcb->AuthGroup,
459                                                   &pCcb->DirectoryCB->NameInformation.FileName,
460                                                   &pObjectInfo->FileId,
461                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
462                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
463                                                   &stFileCleanup,
464                                                   sizeof( AFSFileCleanupCB),
465                                                   pResultCB,
466                                                   &ulResultLen);
467
468                     if( !NT_SUCCESS( ntStatus) &&
469                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
470                     {
471
472                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
473                                       AFS_TRACE_LEVEL_ERROR,
474                                       "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
475                                       &pCcb->FullFileName,
476                                       ntStatus);
477
478                         ntStatus = STATUS_SUCCESS;
479
480                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
481                     }
482                     else
483                     {
484
485                         ntStatus = STATUS_SUCCESS;
486
487                         if ( --pObjectInfo->Links < 1)
488                         {
489
490                             //
491                             // Stop anything possibly in process
492                             //
493
494                             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
495                                           AFS_TRACE_LEVEL_VERBOSE,
496                                           "AFSCleanup Acquiring Fcb extents lock %p EXCL %08lX\n",
497                                           &pFcb->NPFcb->Specific.File.ExtentsResource,
498                                           PsGetCurrentThread());
499
500                             AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
501                                             TRUE);
502
503                             pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
504
505                             KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
506                                         0,
507                                         FALSE);
508
509                             //
510                             // The file has been deleted since the Link count is zero
511                             //
512
513                             AFSDeleteFcbExtents( pFcb);
514
515                             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
516                                           AFS_TRACE_LEVEL_VERBOSE,
517                                           "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
518                                           &pFcb->NPFcb->Specific.File.ExtentsResource,
519                                           PsGetCurrentThread());
520
521                             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
522                         }
523
524                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
525                                       AFS_TRACE_LEVEL_VERBOSE,
526                                       "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
527                                       &pCcb->FullFileName,
528                                       pCcb->DirectoryCB);
529
530                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
531
532                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
533
534                         ASSERT( pParentObjectInfo != NULL);
535
536                         if ( pParentObjectInfo != NULL)
537                         {
538
539                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
540                                             TRUE);
541
542                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
543                             {
544
545                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
546
547                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
548                             }
549                             else
550                             {
551
552                                 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
553                             }
554
555                             //
556                             // Now that the service has the entry has deleted we need to remove it from the parent
557                             // tree so another lookup on the node will fail
558                             //
559
560                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
561                             {
562
563                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
564                                               AFS_TRACE_LEVEL_VERBOSE,
565                                               "AFSCleanup DE %p for %wZ removing entry\n",
566                                               pCcb->DirectoryCB,
567                                               &pCcb->DirectoryCB->NameInformation.FileName);
568
569                                 AFSRemoveNameEntry( pParentObjectInfo,
570                                                     pCcb->DirectoryCB);
571                             }
572                             else
573                             {
574
575                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
576                                               AFS_TRACE_LEVEL_VERBOSE,
577                                               "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
578                                               pCcb->DirectoryCB,
579                                               &pCcb->DirectoryCB->NameInformation.FileName);
580                             }
581
582                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
583
584                             AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
585                                                             pCcb,
586                                                             (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
587                                                             (ULONG)FILE_ACTION_REMOVED);
588                         }
589                         else
590                         {
591                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
592                             {
593
594                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
595                                               AFS_TRACE_LEVEL_VERBOSE,
596                                               "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
597                                               pCcb->DirectoryCB,
598                                               &pCcb->DirectoryCB->NameInformation.FileName);
599                             }
600                         }
601                     }
602                 }
603                 else
604                 {
605
606                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
607                         pParentObjectInfo != NULL)
608                     {
609
610                         ULONG ulNotifyFilter = 0;
611
612                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
613
614                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
615
616                         AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
617                                                         pCcb,
618                                                         (ULONG)ulNotifyFilter,
619                                                         (ULONG)FILE_ACTION_MODIFIED);
620                     }
621
622
623                     //
624                     // Whenever a handle with write access or the last handle is closed
625                     // notify the service to FSync the file.  If the redirector is holding
626                     // dirty extents, flush them to the service.  This is a bit aggressive
627                     // but it ensures cache coherency.
628                     //
629
630                     if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
631                     {
632
633                         if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
634                         {
635
636                             AFSFlushExtents( pFcb,
637                                              &pCcb->AuthGroup);
638                         }
639
640                         ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
641                     }
642
643                     if( pFcb->OpenHandleCount == 1)
644                     {
645
646                         //
647                         // Wait for any outstanding queued flushes to complete
648                         //
649
650                         AFSWaitOnQueuedFlushes( pFcb);
651
652                         AFSTearDownFcbExtents( pFcb,
653                                                &pCcb->AuthGroup);
654                     }
655
656                     //
657                     // Indicate the file access mode that is being released
658                     //
659
660                     stFileCleanup.FileAccess = pCcb->FileAccess;
661
662                     //
663                     // Remove the share access at this time since we may not get the close for sometime on this FO.
664                     //
665
666                     IoRemoveShareAccess( pFileObject,
667                                          &pFcb->ShareAccess);
668
669
670                     //
671                     // We don't need the name array after the user closes the handle on the file
672                     //
673
674                     if( pCcb->NameArray != NULL)
675                     {
676
677                         AFSFreeNameArray( pCcb->NameArray);
678
679                         pCcb->NameArray = NULL;
680                     }
681
682                     //
683                     // Release the Fcb Resource across the call to the service
684                     // which may block for quite a while if flushing of the
685                     // data is required.
686                     //
687
688                     AFSReleaseResource( &pFcb->NPFcb->Resource);
689
690                     //
691                     // Push the request to the service
692                     //
693
694                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
695                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
696                                                   &pCcb->AuthGroup,
697                                                   &pCcb->DirectoryCB->NameInformation.FileName,
698                                                   &pObjectInfo->FileId,
699                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
700                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
701                                                   &stFileCleanup,
702                                                   sizeof( AFSFileCleanupCB),
703                                                   pResultCB,
704                                                   &ulResultLen);
705
706                     //
707                     // Regain exclusive access to the Fcb
708                     //
709
710                     AFSAcquireExcl( &pFcb->NPFcb->Resource,
711                                     TRUE);
712
713                     if ( NT_SUCCESS( ntStatus))
714                     {
715
716                         if ( pParentObjectInfo != NULL)
717                         {
718
719                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
720                                             TRUE);
721
722                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
723                             {
724
725                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
726
727                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
728                             }
729
730                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
731                         }
732                     }
733
734                     ntStatus = STATUS_SUCCESS;
735                 }
736
737                 //
738                 // Decrement the open child handle count
739                 //
740
741                 if( pParentObjectInfo != NULL)
742                 {
743
744                     ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
745
746                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
747
748                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
749                                   AFS_TRACE_LEVEL_VERBOSE,
750                                   "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
751                                   pParentObjectInfo,
752                                   lCount);
753                 }
754
755
756                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
757
758                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
759                               AFS_TRACE_LEVEL_VERBOSE,
760                               "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
761                               pFcb,
762                               lCount);
763
764                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
765                 {
766                     //
767                     // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
768                     //
769
770                     lCount = AFSObjectInfoIncrement( pObjectInfo,
771                                                      AFS_OBJECT_REFERENCE_INVALIDATION);
772
773                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
774                                   AFS_TRACE_LEVEL_VERBOSE,
775                                   "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
776                                   pObjectInfo,
777                                   lCount);
778
779                     ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
780
781                     AFSReleaseResource( &pFcb->NPFcb->Resource);
782
783                     AFSPerformObjectInvalidate( pObjectInfo,
784                                                 AFS_INVALIDATE_DATA_VERSION);
785                 }
786                 else
787                 {
788
789                     AFSReleaseResource( &pFcb->NPFcb->Resource);
790                 }
791
792                 break;
793             }
794
795             //
796             // Root or directory node
797             //
798
799             case AFS_ROOT_FCB:
800             {
801
802                 //
803                 // Set the root Fcb to this node
804                 //
805
806                 pRootFcb = pFcb;
807
808                 //
809                 // Fall through to below
810                 //
811             }
812
813             case AFS_DIRECTORY_FCB:
814             {
815
816                 //
817                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
818                 //
819
820                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
821                               AFS_TRACE_LEVEL_VERBOSE,
822                               "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
823                               &pFcb->NPFcb->Resource,
824                               PsGetCurrentThread());
825
826                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
827                                   TRUE);
828
829                 //
830                 // Perform some final common processing
831                 //
832
833                 ASSERT( pFcb->OpenHandleCount != 0);
834
835                 if( pParentObjectInfo != NULL)
836                 {
837
838                     stFileCleanup.ParentId = pParentObjectInfo->FileId;
839                 }
840
841                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
842
843                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
844                 {
845
846                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
847
848                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
849                     {
850
851                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
852
853                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
854                     }
855
856                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
857                     {
858
859                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
860
861                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
862                     }
863
864                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
865                     {
866
867                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
868
869                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
870                     }
871                 }
872
873                 //
874                 // If the count has dropped to one and there is a pending delete
875                 // then delete the node.  The final count will be decremented just
876                 // before the Fcb->NPFcb->Resource is released.
877                 //
878
879                 if( pFcb->OpenHandleCount == 1 &&
880                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
881                 {
882
883                     //
884                     // Try to notify the service about the delete
885                     //
886
887                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
888
889                     //
890                     // Indicate the file access mode that is being released
891                     //
892
893                     stFileCleanup.FileAccess = pCcb->FileAccess;
894
895                     //
896                     // Push the request to the service
897                     //
898
899                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
900                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
901                                                   &pCcb->AuthGroup,
902                                                   &pCcb->DirectoryCB->NameInformation.FileName,
903                                                   &pObjectInfo->FileId,
904                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
905                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
906                                                   &stFileCleanup,
907                                                   sizeof( AFSFileCleanupCB),
908                                                   pResultCB,
909                                                   &ulResultLen);
910
911                     if( !NT_SUCCESS( ntStatus) &&
912                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
913                     {
914
915                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
916                                       AFS_TRACE_LEVEL_ERROR,
917                                       "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
918                                       &pCcb->FullFileName,
919                                       ntStatus);
920
921                         ntStatus = STATUS_SUCCESS;
922
923                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
924                     }
925                     else
926                     {
927
928                         ntStatus = STATUS_SUCCESS;
929
930                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
931                                       AFS_TRACE_LEVEL_VERBOSE,
932                                       "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
933                                       &pCcb->FullFileName,
934                                       pCcb->DirectoryCB);
935
936                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
937
938                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
939
940                         ASSERT( pParentObjectInfo != NULL);
941
942                         if ( pParentObjectInfo != NULL)
943                         {
944
945                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
946                                             TRUE);
947
948                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
949                             {
950
951                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
952
953                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
954                             }
955                             else
956                             {
957
958                                 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
959                             }
960
961                             //
962                             // Now that the service has the entry has deleted we need to remove it from the parent
963                             // tree so another lookup on the node will fail
964                             //
965
966                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
967                             {
968
969                                 AFSRemoveNameEntry( pParentObjectInfo,
970                                                     pCcb->DirectoryCB);
971                             }
972                             else
973                             {
974
975                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
976                                               AFS_TRACE_LEVEL_VERBOSE,
977                                               "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
978                                               pCcb->DirectoryCB,
979                                               &pCcb->DirectoryCB->NameInformation.FileName);
980                             }
981
982                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
983
984                             AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
985                                                             pCcb,
986                                                             (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
987                                                             (ULONG)FILE_ACTION_REMOVED);
988                         }
989                         else
990                         {
991                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
992                             {
993
994                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
995                                               AFS_TRACE_LEVEL_VERBOSE,
996                                               "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
997                                               pCcb->DirectoryCB,
998                                               &pCcb->DirectoryCB->NameInformation.FileName);
999                             }
1000                         }
1001                     }
1002                 }
1003
1004                 //
1005                 // If there have been any updates to the node then push it to
1006                 // the service
1007                 //
1008
1009                 else
1010                 {
1011
1012                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1013                         pParentObjectInfo != NULL)
1014                     {
1015
1016                         ULONG ulNotifyFilter = 0;
1017
1018                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1019
1020                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1021
1022                         AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1023                                                         pCcb,
1024                                                         (ULONG)ulNotifyFilter,
1025                                                         (ULONG)FILE_ACTION_MODIFIED);
1026                     }
1027
1028                     //
1029                     // Indicate the file access mode that is being released
1030                     //
1031
1032                     stFileCleanup.FileAccess = pCcb->FileAccess;
1033
1034                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1035                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1036                                                   &pCcb->AuthGroup,
1037                                                   &pCcb->DirectoryCB->NameInformation.FileName,
1038                                                   &pObjectInfo->FileId,
1039                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
1040                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1041                                                   &stFileCleanup,
1042                                                   sizeof( AFSFileCleanupCB),
1043                                                   pResultCB,
1044                                                   &ulResultLen);
1045
1046                     if ( NT_SUCCESS( ntStatus))
1047                     {
1048
1049                         if ( pParentObjectInfo != NULL)
1050                         {
1051
1052                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1053                                               TRUE);
1054
1055                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1056                             {
1057
1058                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1059
1060                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1061                             }
1062
1063                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1064                         }
1065                     }
1066
1067                     ntStatus = STATUS_SUCCESS;
1068                 }
1069
1070                 //
1071                 // Release the notification for this directory if there is one
1072                 //
1073
1074                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1075                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
1076                                     pCcb);
1077
1078                 //
1079                 // Remove the share access at this time since we may not get the close for sometime on this FO.
1080                 //
1081
1082                 IoRemoveShareAccess( pFileObject,
1083                                      &pFcb->ShareAccess);
1084
1085                 //
1086                 // We don't need the name array after the user closes the handle on the file
1087                 //
1088
1089                 if( pCcb->NameArray != NULL)
1090                 {
1091
1092                     AFSFreeNameArray( pCcb->NameArray);
1093
1094                     pCcb->NameArray = NULL;
1095                 }
1096
1097                 //
1098                 // Decrement the open child handle count
1099                 //
1100
1101                 if( pParentObjectInfo != NULL)
1102                 {
1103
1104                     ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1105
1106                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1107
1108                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1109                                   AFS_TRACE_LEVEL_VERBOSE,
1110                                   "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1111                                   pParentObjectInfo,
1112                                   lCount);
1113                 }
1114
1115                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1116
1117                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1118                               AFS_TRACE_LEVEL_VERBOSE,
1119                               "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1120                               pFcb,
1121                               lCount);
1122
1123                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1124
1125                 break;
1126             }
1127
1128             case AFS_SYMBOLIC_LINK_FCB:
1129             case AFS_MOUNT_POINT_FCB:
1130             case AFS_DFS_LINK_FCB:
1131             case AFS_INVALID_FCB:
1132             {
1133
1134                 //
1135                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1136                 //
1137
1138                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1139                               AFS_TRACE_LEVEL_VERBOSE,
1140                               "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1141                               &pFcb->NPFcb->Resource,
1142                               PsGetCurrentThread());
1143
1144                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1145                                   TRUE);
1146
1147                 //
1148                 // Perform some final common processing
1149                 //
1150
1151                 ASSERT( pFcb->OpenHandleCount != 0);
1152
1153                 if( pParentObjectInfo != NULL)
1154                 {
1155
1156                     stFileCleanup.ParentId = pParentObjectInfo->FileId;
1157                 }
1158
1159                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1160
1161                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1162                 {
1163
1164                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1165
1166                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1167                     {
1168
1169                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1170
1171                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1172                     }
1173
1174                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1175                     {
1176
1177                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1178
1179                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1180                     }
1181
1182                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1183                     {
1184
1185                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1186
1187                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1188                     }
1189                 }
1190
1191                 //
1192                 // If the count has dropped to one and there is a pending delete
1193                 // then delete the node.  The final count will be decremented just
1194                 // before the Fcb->NPFcb->Resource is released.
1195                 //
1196
1197                 if( pFcb->OpenHandleCount == 1 &&
1198                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1199                 {
1200
1201                     //
1202                     // Try to notify the service about the delete
1203                     //
1204
1205                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1206
1207                     //
1208                     // Indicate the file access mode that is being released
1209                     //
1210
1211                     stFileCleanup.FileAccess = pCcb->FileAccess;
1212
1213                     //
1214                     // Push the request to the service
1215                     //
1216
1217                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1218                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1219                                                   &pCcb->AuthGroup,
1220                                                   &pCcb->DirectoryCB->NameInformation.FileName,
1221                                                   &pObjectInfo->FileId,
1222                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
1223                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1224                                                   &stFileCleanup,
1225                                                   sizeof( AFSFileCleanupCB),
1226                                                   pResultCB,
1227                                                   &ulResultLen);
1228
1229                     if( !NT_SUCCESS( ntStatus) &&
1230                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1231                     {
1232
1233                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1234                                       AFS_TRACE_LEVEL_ERROR,
1235                                       "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1236                                       &pCcb->FullFileName,
1237                                       ntStatus);
1238
1239                         ntStatus = STATUS_SUCCESS;
1240
1241                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1242                     }
1243                     else
1244                     {
1245
1246                         ntStatus = STATUS_SUCCESS;
1247
1248                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1249                                       AFS_TRACE_LEVEL_VERBOSE,
1250                                       "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1251                                       &pCcb->FullFileName,
1252                                       pCcb->DirectoryCB);
1253
1254                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1255
1256                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1257
1258                         ASSERT( pParentObjectInfo != NULL);
1259
1260                         if ( pParentObjectInfo != NULL)
1261                         {
1262
1263                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1264                                             TRUE);
1265
1266                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1267                             {
1268
1269                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1270
1271                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1272                             }
1273                             else
1274                             {
1275                                 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1276                             }
1277
1278                             //
1279                             // Now that the service has the entry has deleted we need to remove it from the parent
1280                             // tree so another lookup on the node will fail
1281                             //
1282
1283                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1284                             {
1285
1286                                 AFSRemoveNameEntry( pParentObjectInfo,
1287                                                     pCcb->DirectoryCB);
1288                             }
1289                             else
1290                             {
1291
1292                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1293                                               AFS_TRACE_LEVEL_VERBOSE,
1294                                               "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1295                                               pCcb->DirectoryCB,
1296                                               &pCcb->DirectoryCB->NameInformation.FileName);
1297                             }
1298
1299                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1300
1301                             AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1302                                                             pCcb,
1303                                                             (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1304                                                             (ULONG)FILE_ACTION_REMOVED);
1305                         }
1306                         else
1307                         {
1308
1309                             if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1310                             {
1311
1312                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1313                                               AFS_TRACE_LEVEL_VERBOSE,
1314                                               "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1315                                               pCcb->DirectoryCB,
1316                                               &pCcb->DirectoryCB->NameInformation.FileName);
1317                             }
1318                         }
1319                     }
1320                 }
1321
1322                 //
1323                 // If there have been any updates to the node then push it to
1324                 // the service
1325                 //
1326
1327                 else
1328                 {
1329
1330                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1331                         pParentObjectInfo != NULL)
1332                     {
1333
1334                         ULONG ulNotifyFilter = 0;
1335
1336                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1337
1338                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1339
1340                         AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1341                                                         pCcb,
1342                                                         (ULONG)ulNotifyFilter,
1343                                                         (ULONG)FILE_ACTION_MODIFIED);
1344                     }
1345
1346                     //
1347                     // Indicate the file access mode that is being released
1348                     //
1349
1350                     stFileCleanup.FileAccess = pCcb->FileAccess;
1351
1352                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1353                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1354                                                   &pCcb->AuthGroup,
1355                                                   &pCcb->DirectoryCB->NameInformation.FileName,
1356                                                   &pObjectInfo->FileId,
1357                                                   pObjectInfo->VolumeCB->VolumeInformation.Cell,
1358                                                   pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1359                                                   &stFileCleanup,
1360                                                   sizeof( AFSFileCleanupCB),
1361                                                   pResultCB,
1362                                                   &ulResultLen);
1363
1364                     if ( NT_SUCCESS( ntStatus))
1365                     {
1366
1367                         if ( pParentObjectInfo != NULL)
1368                         {
1369
1370                             AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1371                                               TRUE);
1372
1373                             if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1374                             {
1375
1376                                 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1377
1378                                 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1379                             }
1380
1381                             AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1382                         }
1383                     }
1384
1385                     ntStatus = STATUS_SUCCESS;
1386                 }
1387
1388                 //
1389                 // Remove the share access at this time since we may not get the close for sometime on this FO.
1390                 //
1391
1392                 IoRemoveShareAccess( pFileObject,
1393                                      &pFcb->ShareAccess);
1394
1395                 //
1396                 // We don't need the name array after the user closes the handle on the file
1397                 //
1398
1399                 if( pCcb->NameArray != NULL)
1400                 {
1401
1402                     AFSFreeNameArray( pCcb->NameArray);
1403
1404                     pCcb->NameArray = NULL;
1405                 }
1406
1407                 //
1408                 // Decrement the open child handle count
1409                 //
1410
1411                 if( pParentObjectInfo != NULL)
1412                 {
1413
1414                     ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1415
1416                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1417
1418                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1419                                   AFS_TRACE_LEVEL_VERBOSE,
1420                                   "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1421                                   pParentObjectInfo,
1422                                   lCount);
1423                 }
1424
1425                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1426
1427                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1428                               AFS_TRACE_LEVEL_VERBOSE,
1429                               "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1430                               pFcb,
1431                               lCount);
1432
1433                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1434
1435                 break;
1436             }
1437
1438             case AFS_SPECIAL_SHARE_FCB:
1439             {
1440
1441                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1442                               AFS_TRACE_LEVEL_VERBOSE,
1443                               "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1444                               &pFcb->NPFcb->Resource,
1445                               PsGetCurrentThread());
1446
1447                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1448                                 TRUE);
1449
1450                 ASSERT( pFcb->OpenHandleCount != 0);
1451
1452                 //
1453                 // Decrement the open child handle count
1454                 //
1455
1456                 if( pParentObjectInfo != NULL &&
1457                     pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1458                 {
1459
1460                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1461
1462                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1463                                   AFS_TRACE_LEVEL_VERBOSE,
1464                                   "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1465                                   pParentObjectInfo,
1466                                   lCount);
1467                 }
1468
1469                 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1470
1471                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1472                               AFS_TRACE_LEVEL_VERBOSE,
1473                               "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1474                               pFcb,
1475                               lCount);
1476
1477                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1478
1479                 break;
1480             }
1481
1482             default:
1483
1484                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1485                               AFS_TRACE_LEVEL_ERROR,
1486                               "AFSCleanup Processing unknown node type %d\n",
1487                               pFcb->Header.NodeTypeCode);
1488
1489                 break;
1490         }
1491
1492
1493 try_exit:
1494
1495         if ( pParentObjectInfo != NULL)
1496         {
1497
1498             AFSReleaseObjectInfo( &pParentObjectInfo);
1499         }
1500
1501         if( pResultCB != NULL)
1502         {
1503
1504             AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1505         }
1506
1507         if( pFileObject != NULL)
1508         {
1509
1510             //
1511             // Setup the fileobject flags to indicate cleanup is complete.
1512             //
1513
1514             SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1515         }
1516
1517         //
1518         // Complete the request
1519         //
1520
1521         AFSCompleteRequest( Irp, ntStatus);
1522     }
1523     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1524     {
1525
1526         AFSDbgLogMsg( 0,
1527                       0,
1528                       "EXCEPTION - AFSCleanup\n");
1529
1530         AFSDumpTraceFilesFnc();
1531     }
1532
1533     return ntStatus;
1534 }