[FASTFAT] Fix a handle count leak on volume close. This can prevent locking a volume!
[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 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "vfat.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS ****************************************************************/
17
18 /*
19 * FUNCTION: Cleans up after a file has been closed.
20 */
21 static
22 NTSTATUS
23 VfatCleanupFile(
24 PVFAT_IRP_CONTEXT IrpContext)
25 {
26 PVFATFCB pFcb;
27 PVFATCCB pCcb;
28 BOOLEAN IsVolume;
29 PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
30 PFILE_OBJECT FileObject = IrpContext->FileObject;
31
32 DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
33 IrpContext->DeviceExt, FileObject);
34
35 /* FIXME: handle file/directory deletion here */
36 pFcb = (PVFATFCB)FileObject->FsContext;
37 if (!pFcb)
38 return STATUS_SUCCESS;
39
40 IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
41 if (IsVolume)
42 {
43 pFcb->OpenHandleCount--;
44 DeviceExt->OpenHandleCount--;
45
46 if (pFcb->OpenHandleCount != 0)
47 {
48 IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
49 }
50 }
51 else
52 {
53 if(!ExAcquireResourceExclusiveLite(&pFcb->MainResource,
54 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
55 {
56 return STATUS_PENDING;
57 }
58 if(!ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource,
59 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
60 {
61 ExReleaseResourceLite(&pFcb->MainResource);
62 return STATUS_PENDING;
63 }
64
65 pCcb = FileObject->FsContext2;
66 if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
67 {
68 pFcb->Flags |= FCB_DELETE_PENDING;
69 }
70
71 /* Notify about the cleanup */
72 FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
73 &(IrpContext->DeviceExt->NotifyList),
74 FileObject->FsContext2);
75
76 pFcb->OpenHandleCount--;
77 DeviceExt->OpenHandleCount--;
78
79 if (!vfatFCBIsDirectory(pFcb) &&
80 FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
81 {
82 /* remove all locks this process have on this file */
83 FsRtlFastUnlockAll(&pFcb->FileLock,
84 FileObject,
85 IoGetRequestorProcess(IrpContext->Irp),
86 NULL);
87 }
88
89 if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
90 {
91 VfatUpdateEntry (pFcb, vfatVolumeIsFatX(DeviceExt));
92 }
93
94 if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
95 pFcb->OpenHandleCount == 0)
96 {
97 if (vfatFCBIsDirectory(pFcb) &&
98 !VfatIsDirectoryEmpty(DeviceExt, pFcb))
99 {
100 pFcb->Flags &= ~FCB_DELETE_PENDING;
101 }
102 else
103 {
104 PFILE_OBJECT tmpFileObject;
105 tmpFileObject = pFcb->FileObject;
106 if (tmpFileObject != NULL)
107 {
108 pFcb->FileObject = NULL;
109 CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
110 ObDereferenceObject(tmpFileObject);
111 }
112
113 pFcb->RFCB.ValidDataLength.QuadPart = 0;
114 pFcb->RFCB.FileSize.QuadPart = 0;
115 pFcb->RFCB.AllocationSize.QuadPart = 0;
116 }
117 }
118
119 /* Uninitialize the cache (should be done even if caching was never initialized) */
120 CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
121
122 if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
123 pFcb->OpenHandleCount == 0)
124 {
125 VfatDelEntry(DeviceExt, pFcb, NULL);
126
127 FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
128 &(DeviceExt->NotifyList),
129 (PSTRING)&pFcb->PathNameU,
130 pFcb->PathNameU.Length - pFcb->LongNameU.Length,
131 NULL,
132 NULL,
133 vfatFCBIsDirectory(pFcb) ?
134 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
135 FILE_ACTION_REMOVED,
136 NULL);
137 }
138
139 if (pFcb->OpenHandleCount != 0)
140 {
141 IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
142 }
143
144 FileObject->Flags |= FO_CLEANUP_COMPLETE;
145
146 ExReleaseResourceLite(&pFcb->PagingIoResource);
147 ExReleaseResourceLite(&pFcb->MainResource);
148 }
149
150 #ifdef ENABLE_SWAPOUT
151 if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
152 {
153 VfatCheckForDismount(DeviceExt, FALSE);
154 }
155 #endif
156
157 return STATUS_SUCCESS;
158 }
159
160 /*
161 * FUNCTION: Cleans up after a file has been closed.
162 */
163 NTSTATUS
164 VfatCleanup(
165 PVFAT_IRP_CONTEXT IrpContext)
166 {
167 NTSTATUS Status;
168
169 DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
170
171 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
172 {
173 IrpContext->Irp->IoStatus.Information = 0;
174 return STATUS_SUCCESS;
175 }
176
177 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
178 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
179 {
180 return VfatMarkIrpContextForQueue(IrpContext);
181 }
182
183 Status = VfatCleanupFile(IrpContext);
184
185 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
186
187 if (Status == STATUS_PENDING)
188 {
189 return VfatMarkIrpContextForQueue(IrpContext);
190 }
191
192 IrpContext->Irp->IoStatus.Information = 0;
193 return Status;
194 }
195
196 /* EOF */