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