[FASTFAT] Fix use after free when volume is unmounted
[reactos.git] / drivers / filesystems / fastfat / cleanup.c
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 */