[FASTFAT] Implement delayed close
[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 */
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 /* If that's the last open handle we just closed, try to see whether
132 * we can delay close operation
133 */
134 else if (!BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && !BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE) &&
135 !BooleanFlagOn(pFcb->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME))
136 {
137 /* This is only allowed if that's a directory with no open files
138 * OR if it's a file with no section opened
139 * FIXME: only allow files for now
140 */
141 #if 0
142 if ((vfatFCBIsDirectory(pFcb) && IsListEmpty(&pFcb->ParentListHead)) ||
143 (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
144 FileObject->SectionObjectPointer->ImageSectionObject == NULL))
145 #else
146 if (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
147 FileObject->SectionObjectPointer->ImageSectionObject == NULL)
148 #endif
149 {
150 DPRINT("Delaying close of: %wZ\n", &pFcb->PathNameU);
151 SetFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
152 }
153 }
154
155 FileObject->Flags |= FO_CLEANUP_COMPLETE;
156 #ifdef KDBG
157 pFcb->Flags |= FCB_CLEANED_UP;
158 #endif
159
160 ExReleaseResourceLite(&pFcb->PagingIoResource);
161 ExReleaseResourceLite(&pFcb->MainResource);
162 }
163
164 #ifdef ENABLE_SWAPOUT
165 if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
166 {
167 VfatCheckForDismount(DeviceExt, FALSE);
168 }
169 #endif
170
171 return STATUS_SUCCESS;
172 }
173
174 /*
175 * FUNCTION: Cleans up after a file has been closed.
176 */
177 NTSTATUS
178 VfatCleanup(
179 PVFAT_IRP_CONTEXT IrpContext)
180 {
181 NTSTATUS Status;
182
183 DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
184
185 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
186 {
187 IrpContext->Irp->IoStatus.Information = 0;
188 return STATUS_SUCCESS;
189 }
190
191 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
192 Status = VfatCleanupFile(IrpContext);
193 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
194
195 IrpContext->Irp->IoStatus.Information = 0;
196 return Status;
197 }
198
199 /* EOF */