Windows: Enforce Share Access
[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
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     AFSFileCleanupCB stFileCleanup;
69     ULONG   ulNotificationFlags = 0;
70
71     __try
72     {
73
74         if( AFSRDRDeviceObject == NULL)
75         {
76
77             //
78             // Let this through, it's a cleanup on the library control device
79             //
80
81             try_return( ntStatus);
82         }
83
84         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
85         pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
86
87         //
88         // Set some initial variables to make processing easier
89         //
90
91         pFileObject = pIrpSp->FileObject;
92
93         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
94
95         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
96
97         if( pFcb == NULL)
98         {
99             try_return( ntStatus);
100         }
101
102         pObjectInfo = pFcb->ObjectInformation;
103
104         pRootFcb = pObjectInfo->VolumeCB->RootFcb;
105
106         RtlZeroMemory( &stFileCleanup,
107                        sizeof( AFSFileCleanupCB));
108
109         stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
110
111         stFileCleanup.Identifier = (ULONGLONG)pFileObject;
112
113         //
114         // Perform the cleanup functionality depending on the type of node it is
115         //
116
117         switch( pFcb->Header.NodeTypeCode)
118         {
119
120             case AFS_ROOT_ALL:
121             {
122
123                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
124                               AFS_TRACE_LEVEL_VERBOSE,
125                               "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
126                               &pFcb->NPFcb->Resource,
127                               PsGetCurrentThread());
128
129                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
130                                   TRUE);
131
132                 ASSERT( pFcb->OpenHandleCount != 0);
133
134                 InterlockedDecrement( &pFcb->OpenHandleCount);
135
136                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
137                               AFS_TRACE_LEVEL_VERBOSE,
138                               "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n",
139                               pFcb,
140                               pFcb->OpenHandleCount);
141
142                 AFSReleaseResource( &pFcb->NPFcb->Resource);
143
144                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
145                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
146                                     pCcb);
147
148                 break;
149             }
150
151             case AFS_IOCTL_FCB:
152             {
153
154                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
155                               AFS_TRACE_LEVEL_VERBOSE,
156                               "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n",
157                               &pFcb->NPFcb->Resource,
158                               PsGetCurrentThread());
159
160                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
161                                   TRUE);
162
163                 ASSERT( pFcb->OpenHandleCount != 0);
164
165                 InterlockedDecrement( &pFcb->OpenHandleCount);
166
167                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
168                               AFS_TRACE_LEVEL_VERBOSE,
169                               "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n",
170                               pFcb,
171                               pFcb->OpenHandleCount);
172
173                 //
174                 // Decrement the open child handle count
175                 //
176
177                 if( pObjectInfo->ParentObjectInformation != NULL &&
178                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
179                 {
180
181                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
182
183                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
184                                   AFS_TRACE_LEVEL_VERBOSE,
185                                   "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n",
186                                   pObjectInfo->ParentObjectInformation,
187                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
188                 }
189
190                 //
191                 // And finally, release the Fcb if we acquired it.
192                 //
193
194                 AFSReleaseResource( &pFcb->NPFcb->Resource);
195
196                 break;
197             }
198
199             //
200             // This Fcb represents a file
201             //
202
203             case AFS_FILE_FCB:
204             {
205
206                 //
207                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
208                 //
209
210                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
211                               AFS_TRACE_LEVEL_VERBOSE,
212                               "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n",
213                               &pFcb->NPFcb->Resource,
214                               PsGetCurrentThread());
215
216                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
217                                 TRUE);
218
219                 //
220                 // Uninitialize the cache map. This call is unconditional.
221                 //
222
223                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
224                               AFS_TRACE_LEVEL_VERBOSE,
225                               "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n",
226                               pFcb,
227                               pFileObject);
228
229                 CcUninitializeCacheMap( pFileObject,
230                                         NULL,
231                                         NULL);
232
233                 //
234                 // Unlock all outstanding locks on the file, again, unconditionally
235                 //
236
237                 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
238                                            pFileObject,
239                                            IoGetRequestorProcess( Irp),
240                                            NULL);
241
242                 //
243                 // Tell the service to unlock all on the file
244                 //
245
246                 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
247
248                 //
249                 // Perform some final common processing
250                 //
251
252                 ASSERT( pFcb->OpenHandleCount != 0);
253
254                 InterlockedDecrement( &pFcb->OpenHandleCount);
255
256                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
257                               AFS_TRACE_LEVEL_VERBOSE,
258                               "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n",
259                               pFcb,
260                               pFcb->OpenHandleCount);
261
262                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
263                 {
264
265                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
266                 }
267
268                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
269
270                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
271                 {
272
273                     stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
274
275                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
276
277                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
278                     {
279
280                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
281
282                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
283                     }
284
285                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
286                     {
287
288                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
289
290                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
291                     }
292
293                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
294                     {
295
296                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
297
298                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
299                     }
300
301                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
302                     {
303
304                         stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
305
306                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
307                     }
308                 }
309
310                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
311                 {
312
313                     stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
314                 }
315
316                 //
317                 // If the count has dropped to zero and there is a pending delete
318                 // then delete the node
319                 //
320
321                 if( pFcb->OpenHandleCount == 0 &&
322                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
323                 {
324
325                     //
326                     // Stop anything possibly in process
327                     //
328
329                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
330                                   AFS_TRACE_LEVEL_VERBOSE,
331                                   "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n",
332                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
333                                   PsGetCurrentThread());
334
335                     AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
336                                     TRUE);
337
338                     pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
339
340                     KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
341                                 0,
342                                 FALSE);
343
344                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
345                                   AFS_TRACE_LEVEL_VERBOSE,
346                                   "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n",
347                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
348                                   PsGetCurrentThread());
349
350                     AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
351
352                     //
353                     // Before telling the server about the deleted file, tear down all extents for
354                     // the file
355                     //
356
357                     AFSTearDownFcbExtents( pFcb);
358
359                     ntStatus = STATUS_SUCCESS;
360
361                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
362
363                     //
364                     // Indicate the file access mode that is being released
365                     //
366
367                     stFileCleanup.FileAccess = pCcb->FileAccess;
368
369                     //
370                     // Push the request to the service
371                     //
372
373                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
374                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
375                                                   &pFcb->AuthGroup,
376                                                   &pCcb->DirectoryCB->NameInformation.FileName,
377                                                   &pObjectInfo->FileId,
378                                                   &stFileCleanup,
379                                                   sizeof( AFSFileCleanupCB),
380                                                   NULL,
381                                                   NULL);
382
383                     if( !NT_SUCCESS( ntStatus) &&
384                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
385                     {
386
387                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
388                                       AFS_TRACE_LEVEL_ERROR,
389                                       "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
390                                       &pCcb->FullFileName,
391                                       ntStatus);
392
393                         ntStatus = STATUS_SUCCESS;
394
395                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
396                     }
397                     else
398                     {
399
400                         ntStatus = STATUS_SUCCESS;
401
402                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
403                                       AFS_TRACE_LEVEL_VERBOSE,
404                                       "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
405                                       &pCcb->FullFileName,
406                                       pCcb->DirectoryCB);
407
408                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
409
410                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
411
412                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
413                                                         pCcb,
414                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
415                                                         (ULONG)FILE_ACTION_REMOVED);
416
417                         //
418                         // Now that the service has the entry has deleted we need to remove it from the parent
419                         // tree so another lookup on the node will fail
420                         //
421
422                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
423                         {
424
425                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
426                                             TRUE);
427
428                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
429                                           AFS_TRACE_LEVEL_VERBOSE,
430                                           "AFSCleanup DE %p for %wZ removing entry\n",
431                                           pCcb->DirectoryCB,
432                                           &pCcb->DirectoryCB->NameInformation.FileName);
433
434                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
435                                                 pCcb->DirectoryCB);
436
437                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
438                         }
439                         else
440                         {
441
442                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
443                                           AFS_TRACE_LEVEL_VERBOSE,
444                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
445                                           pCcb->DirectoryCB,
446                                           &pCcb->DirectoryCB->NameInformation.FileName);
447                         }
448                     }
449                 }
450                 else
451                 {
452
453                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
454                     {
455
456                         ULONG ulNotifyFilter = 0;
457
458                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
459
460                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
461
462                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
463                                                         pCcb,
464                                                         (ULONG)ulNotifyFilter,
465                                                         (ULONG)FILE_ACTION_MODIFIED);
466                     }
467
468                     //
469                     // Flush out any dirty pages on every handle close to reduce strain on the afs cache
470                     //
471
472                     if( CcIsFileCached( pIrpSp->FileObject))
473                     {
474
475                         __try
476                         {
477
478                             CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
479                                           NULL,
480                                           0,
481                                           &stIoSB);
482
483                             if( !NT_SUCCESS( stIoSB.Status))
484                             {
485
486                                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
487                                               AFS_TRACE_LEVEL_ERROR,
488                                               "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
489                                               &pCcb->FullFileName,
490                                               pObjectInfo->FileId.Cell,
491                                               pObjectInfo->FileId.Volume,
492                                               pObjectInfo->FileId.Vnode,
493                                               pObjectInfo->FileId.Unique,
494                                               stIoSB.Status,
495                                               stIoSB.Information);
496
497                                 ntStatus = stIoSB.Status;
498                             }
499                         }
500                         __except( EXCEPTION_EXECUTE_HANDLER)
501                         {
502
503                             ntStatus = GetExceptionCode();
504                         }
505                     }
506
507                     //
508                     // Attempt to flush any dirty extents to the server. This may be a little
509                     // aggressive, to flush whenever the handle is closed, but it ensures
510                     // coherency.
511                     //
512
513                     if( pFcb->Specific.File.ExtentsDirtyCount)
514                     {
515
516                         AFSFlushExtents( pFcb);
517                     }
518
519                     if( pFcb->OpenHandleCount == 0)
520                     {
521
522                         //
523                         // Wait for any outstanding queued flushes to complete
524                         //
525
526                         AFSWaitOnQueuedFlushes( pFcb);
527
528                         ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
529                     }
530
531                     //
532                     // Indicate the file access mode that is being released
533                     //
534
535                     stFileCleanup.FileAccess = pCcb->FileAccess;
536
537                     //
538                     // Push the request to the service
539                     //
540
541                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
542                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
543                                        &pFcb->AuthGroup,
544                                        &pCcb->DirectoryCB->NameInformation.FileName,
545                                        &pObjectInfo->FileId,
546                                        &stFileCleanup,
547                                        sizeof( AFSFileCleanupCB),
548                                        NULL,
549                                        NULL);
550                 }
551
552                 //
553                 // Remove the share access at this time since we may not get the close for sometime on this FO.
554                 //
555
556                 IoRemoveShareAccess( pFileObject,
557                                      &pFcb->ShareAccess);
558
559                 //
560                 // We don't need the name array after the user closes the handle on the file
561                 //
562
563                 if( pCcb->NameArray != NULL)
564                 {
565
566                     AFSFreeNameArray( pCcb->NameArray);
567
568                     pCcb->NameArray = NULL;
569                 }
570
571                 //
572                 // Decrement the open child handle count
573                 //
574
575                 if( pObjectInfo->ParentObjectInformation != NULL)
576                 {
577
578                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
579
580                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
581
582                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
583                                   AFS_TRACE_LEVEL_VERBOSE,
584                                   "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
585                                   pObjectInfo->ParentObjectInformation,
586                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
587                 }
588
589                 //
590                 // And finally, release the Fcb if we acquired it.
591                 //
592
593                 AFSReleaseResource( &pFcb->NPFcb->Resource);
594
595                 break;
596             }
597
598             //
599             // Root or directory node
600             //
601
602             case AFS_ROOT_FCB:
603             {
604
605                 //
606                 // Set the root Fcb to this node
607                 //
608
609                 pRootFcb = pFcb;
610
611                 //
612                 // Fall through to below
613                 //
614             }
615
616             case AFS_DIRECTORY_FCB:
617             {
618
619                 //
620                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
621                 //
622
623                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
624                               AFS_TRACE_LEVEL_VERBOSE,
625                               "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
626                               &pFcb->NPFcb->Resource,
627                               PsGetCurrentThread());
628
629                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
630                                   TRUE);
631
632                 //
633                 // Perform some final common processing
634                 //
635
636                 ASSERT( pFcb->OpenHandleCount != 0);
637
638                 InterlockedDecrement( &pFcb->OpenHandleCount);
639
640                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
641                               AFS_TRACE_LEVEL_VERBOSE,
642                               "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
643                               pFcb,
644                               pFcb->OpenHandleCount);
645
646                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
647                 {
648
649                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
650                 }
651
652                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
653
654                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
655                 {
656
657                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
658
659                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
660                     {
661
662                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
663
664                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
665                     }
666
667                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
668                     {
669
670                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
671
672                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
673                     }
674
675                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
676                     {
677
678                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
679
680                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
681                     }
682                 }
683
684                 //
685                 // If the count has dropped to zero and there is a pending delete
686                 // then delete the node
687                 //
688
689                 if( pFcb->OpenHandleCount == 0 &&
690                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
691                 {
692
693                     //
694                     // Try to notify the service about the delete
695                     //
696
697                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
698
699                     //
700                     // Indicate the file access mode that is being released
701                     //
702
703                     stFileCleanup.FileAccess = pCcb->FileAccess;
704
705                     //
706                     // Push the request to the service
707                     //
708
709                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
710                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
711                                                   &pFcb->AuthGroup,
712                                                   &pCcb->DirectoryCB->NameInformation.FileName,
713                                                   &pObjectInfo->FileId,
714                                                   &stFileCleanup,
715                                                   sizeof( AFSFileCleanupCB),
716                                                   NULL,
717                                                   NULL);
718
719                     if( !NT_SUCCESS( ntStatus) &&
720                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
721                     {
722
723                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
724                                       AFS_TRACE_LEVEL_ERROR,
725                                       "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
726                                       &pCcb->FullFileName,
727                                       ntStatus);
728
729                         ntStatus = STATUS_SUCCESS;
730
731                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
732                     }
733                     else
734                     {
735
736                         ntStatus = STATUS_SUCCESS;
737
738                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
739                                       AFS_TRACE_LEVEL_VERBOSE,
740                                       "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
741                                       &pCcb->FullFileName,
742                                       pCcb->DirectoryCB);
743
744                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
745
746                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
747
748                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
749                                                         pCcb,
750                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
751                                                         (ULONG)FILE_ACTION_REMOVED);
752
753                         //
754                         // Now that the service has the entry has deleted we need to remove it from the parent
755                         // tree so another lookup on the node will fail
756                         //
757
758                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
759                         {
760
761                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
762                                             TRUE);
763
764                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
765                                                 pCcb->DirectoryCB);
766
767                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
768                         }
769                         else
770                         {
771
772                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
773                                           AFS_TRACE_LEVEL_VERBOSE,
774                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
775                                           pCcb->DirectoryCB,
776                                           &pCcb->DirectoryCB->NameInformation.FileName);
777                         }
778                     }
779                 }
780
781                 //
782                 // If there have been any updates to the node then push it to
783                 // the service
784                 //
785
786                 else
787                 {
788
789                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
790                     {
791
792                         ULONG ulNotifyFilter = 0;
793
794                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
795
796                         if(  pObjectInfo->ParentObjectInformation != NULL)
797                         {
798
799                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
800
801                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
802                                                             pCcb,
803                                                             (ULONG)ulNotifyFilter,
804                                                             (ULONG)FILE_ACTION_MODIFIED);
805                         }
806                     }
807
808                     //
809                     // Indicate the file access mode that is being released
810                     //
811
812                     stFileCleanup.FileAccess = pCcb->FileAccess;
813
814                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
815                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
816                                        &pFcb->AuthGroup,
817                                        &pCcb->DirectoryCB->NameInformation.FileName,
818                                        &pObjectInfo->FileId,
819                                        &stFileCleanup,
820                                        sizeof( AFSFileCleanupCB),
821                                        NULL,
822                                        NULL);
823                 }
824
825                 //
826                 // Release the notification for this directory if there is one
827                 //
828
829                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
830                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
831                                     pCcb);
832
833                 //
834                 // Remove the share access at this time since we may not get the close for sometime on this FO.
835                 //
836
837                 IoRemoveShareAccess( pFileObject,
838                                      &pFcb->ShareAccess);
839
840                 //
841                 // We don't need the name array after the user closes the handle on the file
842                 //
843
844                 if( pCcb->NameArray != NULL)
845                 {
846
847                     AFSFreeNameArray( pCcb->NameArray);
848
849                     pCcb->NameArray = NULL;
850                 }
851
852                 //
853                 // Decrement the open child handle count
854                 //
855
856                 if( pObjectInfo->ParentObjectInformation != NULL)
857                 {
858
859                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
860
861                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
862
863                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
864                                   AFS_TRACE_LEVEL_VERBOSE,
865                                   "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
866                                   pObjectInfo->ParentObjectInformation,
867                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
868                 }
869
870                 //
871                 // And finally, release the Fcb if we acquired it.
872                 //
873
874                 AFSReleaseResource( &pFcb->NPFcb->Resource);
875
876                 break;
877             }
878
879             case AFS_SYMBOLIC_LINK_FCB:
880             case AFS_MOUNT_POINT_FCB:
881             case AFS_DFS_LINK_FCB:
882             {
883
884                 //
885                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
886                 //
887
888                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
889                               AFS_TRACE_LEVEL_VERBOSE,
890                               "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
891                               &pFcb->NPFcb->Resource,
892                               PsGetCurrentThread());
893
894                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
895                                   TRUE);
896
897                 //
898                 // Perform some final common processing
899                 //
900
901                 ASSERT( pFcb->OpenHandleCount != 0);
902
903                 InterlockedDecrement( &pFcb->OpenHandleCount);
904
905                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
906                               AFS_TRACE_LEVEL_VERBOSE,
907                               "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
908                               pFcb,
909                               pFcb->OpenHandleCount);
910
911                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
912                 {
913
914                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
915                 }
916
917                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
918
919                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
920                 {
921
922                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
923
924                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
925                     {
926
927                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
928
929                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
930                     }
931
932                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
933                     {
934
935                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
936
937                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
938                     }
939
940                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
941                     {
942
943                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
944
945                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
946                     }
947                 }
948
949                 //
950                 // If the count has dropped to zero and there is a pending delete
951                 // then delete the node
952                 //
953
954                 if( pFcb->OpenHandleCount == 0 &&
955                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
956                 {
957
958                     //
959                     // Try to notify the service about the delete
960                     //
961
962                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
963
964                     //
965                     // Indicate the file access mode that is being released
966                     //
967
968                     stFileCleanup.FileAccess = pCcb->FileAccess;
969
970                     //
971                     // Push the request to the service
972                     //
973
974                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
975                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
976                                                   &pFcb->AuthGroup,
977                                                   &pCcb->DirectoryCB->NameInformation.FileName,
978                                                   &pObjectInfo->FileId,
979                                                   &stFileCleanup,
980                                                   sizeof( AFSFileCleanupCB),
981                                                   NULL,
982                                                   NULL);
983
984                     if( !NT_SUCCESS( ntStatus) &&
985                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
986                     {
987
988                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
989                                       AFS_TRACE_LEVEL_ERROR,
990                                       "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
991                                       &pCcb->FullFileName,
992                                       ntStatus);
993
994                         ntStatus = STATUS_SUCCESS;
995
996                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
997                     }
998                     else
999                     {
1000
1001                         ntStatus = STATUS_SUCCESS;
1002
1003                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1004                                       AFS_TRACE_LEVEL_VERBOSE,
1005                                       "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1006                                       &pCcb->FullFileName,
1007                                       pCcb->DirectoryCB);
1008
1009                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1010
1011                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
1012
1013                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1014                                                         pCcb,
1015                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1016                                                         (ULONG)FILE_ACTION_REMOVED);
1017
1018                         //
1019                         // Now that the service has the entry has deleted we need to remove it from the parent
1020                         // tree so another lookup on the node will fail
1021                         //
1022
1023                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1024                         {
1025
1026                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
1027                                             TRUE);
1028
1029                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
1030                                                 pCcb->DirectoryCB);
1031
1032                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1033                         }
1034                         else
1035                         {
1036
1037                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1038                                           AFS_TRACE_LEVEL_VERBOSE,
1039                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1040                                           pCcb->DirectoryCB,
1041                                           &pCcb->DirectoryCB->NameInformation.FileName);
1042                         }
1043                     }
1044                 }
1045
1046                 //
1047                 // If there have been any updates to the node then push it to
1048                 // the service
1049                 //
1050
1051                 else
1052                 {
1053
1054                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1055                     {
1056
1057                         ULONG ulNotifyFilter = 0;
1058
1059                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1060
1061                         if(  pObjectInfo->ParentObjectInformation != NULL)
1062                         {
1063
1064                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1065
1066                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1067                                                             pCcb,
1068                                                             (ULONG)ulNotifyFilter,
1069                                                             (ULONG)FILE_ACTION_MODIFIED);
1070                         }
1071                     }
1072
1073                     //
1074                     // Indicate the file access mode that is being released
1075                     //
1076
1077                     stFileCleanup.FileAccess = pCcb->FileAccess;
1078
1079                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1080                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1081                                        &pFcb->AuthGroup,
1082                                        &pCcb->DirectoryCB->NameInformation.FileName,
1083                                        &pObjectInfo->FileId,
1084                                        &stFileCleanup,
1085                                        sizeof( AFSFileCleanupCB),
1086                                        NULL,
1087                                        NULL);
1088                 }
1089
1090                 //
1091                 // Remove the share access at this time since we may not get the close for sometime on this FO.
1092                 //
1093
1094                 IoRemoveShareAccess( pFileObject,
1095                                      &pFcb->ShareAccess);
1096
1097                 //
1098                 // We don't need the name array after the user closes the handle on the file
1099                 //
1100
1101                 if( pCcb->NameArray != NULL)
1102                 {
1103
1104                     AFSFreeNameArray( pCcb->NameArray);
1105
1106                     pCcb->NameArray = NULL;
1107                 }
1108
1109                 //
1110                 // Decrement the open child handle count
1111                 //
1112
1113                 if( pObjectInfo->ParentObjectInformation != NULL)
1114                 {
1115
1116                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
1117
1118                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1119
1120                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1121                                   AFS_TRACE_LEVEL_VERBOSE,
1122                                   "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1123                                   pObjectInfo->ParentObjectInformation,
1124                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1125                 }
1126
1127                 //
1128                 // And finally, release the Fcb if we acquired it.
1129                 //
1130
1131                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1132
1133                 break;
1134             }
1135
1136             case AFS_SPECIAL_SHARE_FCB:
1137             {
1138
1139                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1140                               AFS_TRACE_LEVEL_VERBOSE,
1141                               "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1142                               &pFcb->NPFcb->Resource,
1143                               PsGetCurrentThread());
1144
1145                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1146                                 TRUE);
1147
1148                 ASSERT( pFcb->OpenHandleCount != 0);
1149
1150                 InterlockedDecrement( &pFcb->OpenHandleCount);
1151
1152                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1153                               AFS_TRACE_LEVEL_VERBOSE,
1154                               "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1155                               pFcb,
1156                               pFcb->OpenHandleCount);
1157
1158                 //
1159                 // Decrement the open child handle count
1160                 //
1161
1162                 if( pObjectInfo->ParentObjectInformation != NULL &&
1163                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
1164                 {
1165
1166                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1167
1168                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1169                                   AFS_TRACE_LEVEL_VERBOSE,
1170                                   "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1171                                   pObjectInfo->ParentObjectInformation,
1172                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1173                 }
1174
1175                 //
1176                 // And finally, release the Fcb if we acquired it.
1177                 //
1178
1179                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1180
1181                 break;
1182             }
1183
1184             default:
1185
1186                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1187                               AFS_TRACE_LEVEL_WARNING,
1188                               "AFSCleanup Processing unknown node type %d\n",
1189                               pFcb->Header.NodeTypeCode);
1190
1191                 break;
1192         }
1193
1194
1195 try_exit:
1196
1197         if( pFileObject != NULL)
1198         {
1199
1200             //
1201             // Setup the fileobject flags to indicate cleanup is complete.
1202             //
1203
1204             SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1205         }
1206
1207         //
1208         // Complete the request
1209         //
1210
1211         AFSCompleteRequest( Irp, ntStatus);
1212     }
1213     __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
1214     {
1215
1216         AFSDbgLogMsg( 0,
1217                       0,
1218                       "EXCEPTION - AFSCleanup\n");
1219     }
1220
1221     return ntStatus;
1222 }