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