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