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