1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * FILE:             drivers/fs/vfat/cleanup.c
5  * PURPOSE:          VFAT Filesystem
6  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
7  *                   Pierre Schweitzer (pierre@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "vfat.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* FUNCTIONS ****************************************************************/
18 
19 /*
20  * FUNCTION: Cleans up after a file has been closed.
21  */
22 static
23 NTSTATUS
24 VfatCleanupFile(
25     PVFAT_IRP_CONTEXT IrpContext)
26 {
27     PVFATFCB pFcb;
28     PVFATCCB pCcb;
29     BOOLEAN IsVolume;
30     PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
31     PFILE_OBJECT FileObject = IrpContext->FileObject;
32 
33     DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
34            IrpContext->DeviceExt, FileObject);
35 
36     /* FIXME: handle file/directory deletion here */
37     pFcb = (PVFATFCB)FileObject->FsContext;
38     if (!pFcb)
39         return STATUS_SUCCESS;
40 
41     IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
42     if (IsVolume)
43     {
44         pFcb->OpenHandleCount--;
45         DeviceExt->OpenHandleCount--;
46 
47         if (pFcb->OpenHandleCount != 0)
48         {
49             IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
50         }
51     }
52     else
53     {
54         ExAcquireResourceExclusiveLite(&pFcb->MainResource, TRUE);
55         ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource, TRUE);
56 
57         pCcb = FileObject->FsContext2;
58         if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
59         {
60             pFcb->Flags |= FCB_DELETE_PENDING;
61         }
62 
63         /* Notify about the cleanup */
64         FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
65                            &(IrpContext->DeviceExt->NotifyList),
66                            FileObject->FsContext2);
67 
68         pFcb->OpenHandleCount--;
69         DeviceExt->OpenHandleCount--;
70 
71         if (!vfatFCBIsDirectory(pFcb) &&
72             FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
73         {
74             /* remove all locks this process have on this file */
75             FsRtlFastUnlockAll(&pFcb->FileLock,
76                                FileObject,
77                                IoGetRequestorProcess(IrpContext->Irp),
78                                NULL);
79         }
80 
81         if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
82         {
83             VfatUpdateEntry (DeviceExt, pFcb);
84         }
85 
86         if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
87             pFcb->OpenHandleCount == 0)
88         {
89             if (vfatFCBIsDirectory(pFcb) &&
90                 !VfatIsDirectoryEmpty(DeviceExt, pFcb))
91             {
92                 pFcb->Flags &= ~FCB_DELETE_PENDING;
93             }
94             else
95             {
96                 PFILE_OBJECT tmpFileObject;
97                 tmpFileObject = pFcb->FileObject;
98                 if (tmpFileObject != NULL)
99                 {
100                     pFcb->FileObject = NULL;
101                     CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
102                     ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
103                     ObDereferenceObject(tmpFileObject);
104                 }
105 
106                 pFcb->RFCB.ValidDataLength.QuadPart = 0;
107                 pFcb->RFCB.FileSize.QuadPart = 0;
108                 pFcb->RFCB.AllocationSize.QuadPart = 0;
109             }
110         }
111 
112         /* Uninitialize the cache (should be done even if caching was never initialized) */
113         CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
114 
115         if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
116             pFcb->OpenHandleCount == 0)
117         {
118             VfatDelEntry(DeviceExt, pFcb, NULL);
119 
120             vfatReportChange(DeviceExt,
121                              pFcb,
122                              (vfatFCBIsDirectory(pFcb) ?
123                               FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
124                              FILE_ACTION_REMOVED);
125         }
126 
127         if (pFcb->OpenHandleCount != 0)
128         {
129             IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
130         }
131 /* FIXME: causes FS corruption and breaks selfhosting/testbots and so on */
132 #if 0
133         /* If that's the last open handle we just closed, try to see whether
134          * we can delay close operation
135          */
136         else if (!BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && !BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE) &&
137                  !BooleanFlagOn(pFcb->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME))
138         {
139             /* This is only allowed if that's a directory with no open files
140              * OR if it's a file with no section opened
141              */
142             if ((vfatFCBIsDirectory(pFcb) && IsListEmpty(&pFcb->ParentListHead)) ||
143                 (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
144                  FileObject->SectionObjectPointer->ImageSectionObject == NULL))
145             {
146                 DPRINT("Delaying close of: %wZ\n", &pFcb->PathNameU);
147                 SetFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
148             }
149         }
150 #endif
151 
152         FileObject->Flags |= FO_CLEANUP_COMPLETE;
153 #ifdef KDBG
154         pFcb->Flags |= FCB_CLEANED_UP;
155 #endif
156 
157         ExReleaseResourceLite(&pFcb->PagingIoResource);
158         ExReleaseResourceLite(&pFcb->MainResource);
159     }
160 
161 #ifdef ENABLE_SWAPOUT
162     if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
163     {
164         VfatCheckForDismount(DeviceExt, TRUE);
165     }
166 #endif
167 
168     return STATUS_SUCCESS;
169 }
170 
171 /*
172  * FUNCTION: Cleans up after a file has been closed.
173  */
174 NTSTATUS
175 VfatCleanup(
176     PVFAT_IRP_CONTEXT IrpContext)
177 {
178     NTSTATUS Status;
179 
180     DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
181 
182     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
183     {
184         IrpContext->Irp->IoStatus.Information = 0;
185         return STATUS_SUCCESS;
186     }
187 
188     ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
189     Status = VfatCleanupFile(IrpContext);
190     ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
191 
192     IrpContext->Irp->IoStatus.Information = 0;
193     return Status;
194 }
195 
196 /* EOF */
197