[FS_REC]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / cleanup.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/cleanup.c
5 * PURPOSE: Cleanup routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS ****************************************************************/
15
16 /* Last handle to a file object is closed */
17 NTSTATUS
18 NTAPI
19 FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
20 {
21 PIO_STACK_LOCATION IrpSp;
22 PFILE_OBJECT FileObject;
23 TYPE_OF_OPEN TypeOfOpen;
24 PSHARE_ACCESS ShareAccess;
25 BOOLEAN SendUnlockNotification = FALSE;
26 PLARGE_INTEGER TruncateSize = NULL;
27 //LARGE_INTEGER LocalTruncateSize;
28 BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE;
29 NTSTATUS Status;
30 PVCB Vcb;
31 PFCB Fcb;
32 PCCB Ccb;
33
34 IrpSp = IoGetCurrentIrpStackLocation( Irp );
35
36 DPRINT("FatiCleanup\n");
37 DPRINT("\tIrp = %p\n", Irp);
38 DPRINT("\t->FileObject = %p\n", IrpSp->FileObject);
39
40 FileObject = IrpSp->FileObject;
41 TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);
42
43 if (TypeOfOpen == UnopenedFileObject)
44 {
45 DPRINT1("Unopened File Object\n");
46
47 FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
48 return STATUS_SUCCESS;
49 }
50
51 if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ))
52 {
53 /* Just flush the file */
54
55 if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
56 FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
57 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) &&
58 (TypeOfOpen == UserFileOpen))
59 {
60 //Status = FatFlushFile(IrpContext, Fcb, Flush);
61 //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status);
62 UNIMPLEMENTED;
63 }
64
65 FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
66 return STATUS_SUCCESS;
67 }
68
69 if (TypeOfOpen == UserFileOpen ||
70 TypeOfOpen == UserDirectoryOpen)
71 {
72 ASSERT(Fcb != NULL);
73
74 (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
75
76 AcquiredFcb = TRUE;
77
78 /* Set FCB flags according to DELETE_ON_CLOSE */
79 if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))
80 {
81 ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB);
82
83 SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE);
84
85 /* Issue a notification */
86 if (TypeOfOpen == UserDirectoryOpen)
87 {
88 FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
89 &Vcb->NotifyList,
90 FileObject->FsContext,
91 NULL,
92 FALSE,
93 FALSE,
94 0,
95 NULL,
96 NULL,
97 NULL);
98 }
99 }
100
101 /* If file should be deleted, acquire locks */
102 if ((Fcb->UncleanCount == 1) &&
103 FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
104 (Fcb->Condition != FcbBad) &&
105 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
106 {
107 FatReleaseFcb(IrpContext, Fcb);
108 AcquiredFcb = FALSE;
109
110 (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
111 AcquiredVcb = TRUE;
112
113 (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
114 AcquiredFcb = TRUE;
115 }
116 }
117
118 /* Acquire VCB lock if it was a volume open */
119 if (TypeOfOpen == UserVolumeOpen)
120 {
121 (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
122 AcquiredVcb = TRUE;
123 }
124
125 /* Cleanup all notifications */
126 if (TypeOfOpen == UserDirectoryOpen)
127 {
128 FsRtlNotifyCleanup(Vcb->NotifySync,
129 &Vcb->NotifyList,
130 Ccb);
131 }
132
133 if (Fcb)
134 {
135 //TODO: FatVerifyFcb
136 }
137
138 switch (TypeOfOpen)
139 {
140 case DirectoryFile:
141 case VirtualVolumeFile:
142 DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n");
143 ShareAccess = NULL;
144 break;
145
146 case UserVolumeOpen:
147 DPRINT("Cleanup UserVolumeOpen\n");
148
149 if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT))
150 {
151 FatCheckForDismount( IrpContext, Vcb, TRUE );
152 } else if (FileObject->WriteAccess &&
153 FlagOn(FileObject->Flags, FO_FILE_MODIFIED))
154 {
155 UNIMPLEMENTED;
156 }
157
158 /* Release the volume and send notification */
159 if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) &&
160 (Vcb->FileObjectWithVcbLocked == FileObject))
161 {
162 UNIMPLEMENTED;
163 SendUnlockNotification = TRUE;
164 }
165
166 ShareAccess = &Vcb->ShareAccess;
167 break;
168
169 case EaFile:
170 DPRINT1("Cleanup EaFileObject\n");
171 ShareAccess = NULL;
172 break;
173
174 case UserDirectoryOpen:
175 DPRINT("Cleanup UserDirectoryOpen\n");
176
177 ShareAccess = &Fcb->ShareAccess;
178
179 /* Should it be a delayed close? */
180 if ((Fcb->UncleanCount == 1) &&
181 (Fcb->OpenCount == 1) &&
182 (Fcb->Dcb.DirectoryFileOpenCount == 0) &&
183 !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
184 Fcb->Condition == FcbGood)
185 {
186 /* Yes, a delayed one */
187 SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
188 }
189
190 if (VcbGood == Vcb->Condition)
191 {
192 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
193 //TODO: Actually update dirent
194 }
195
196 if ((Fcb->UncleanCount == 1) &&
197 (FatNodeType(Fcb) == FAT_NTC_DCB) &&
198 (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) &&
199 (Fcb->Condition != FcbBad) &&
200 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
201 {
202 UNIMPLEMENTED;
203 }
204
205 /* Decrement unclean counter */
206 ASSERT(Fcb->UncleanCount != 0);
207 Fcb->UncleanCount--;
208 break;
209
210 case UserFileOpen:
211 DPRINT("Cleanup UserFileOpen\n");
212
213 ShareAccess = &Fcb->ShareAccess;
214
215 /* Should it be a delayed close? */
216 if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
217 (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
218 (Fcb->UncleanCount == 1) &&
219 (Fcb->OpenCount == 1) &&
220 !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
221 Fcb->Condition == FcbGood)
222 {
223 /* Yes, a delayed one */
224 //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
225 DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName);
226 }
227
228 /* Unlock all file locks */
229 FsRtlFastUnlockAll(&Fcb->Fcb.Lock,
230 FileObject,
231 IoGetRequestorProcess(Irp),
232 NULL);
233
234 if (Vcb->Condition == VcbGood)
235 {
236 if (Fcb->Condition != FcbBad)
237 {
238 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
239 // TODO: Update on-disk structures
240 }
241
242 if (Fcb->UncleanCount == 1 &&
243 Fcb->Condition != FcbBad)
244 {
245 //DELETE_CONTEXT DeleteContext;
246
247 /* Should this file be deleted on close? */
248 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
249 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
250 {
251 UNIMPLEMENTED;
252 }
253 else
254 {
255 if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
256 (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart))
257 {
258 #if 0
259 ULONG ValidDataLength;
260
261 ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
262
263 if (ValidDataLength < Fcb->ValidDataToDisk) {
264 ValidDataLength = Fcb->ValidDataToDisk;
265 }
266
267 if (ValidDataLength < Fcb->Header.FileSize.LowPart)
268 {
269 FatZeroData( IrpContext,
270 Vcb,
271 FileObject,
272 ValidDataLength,
273 Fcb->Header.FileSize.LowPart -
274 ValidDataLength );
275
276 Fcb->ValidDataToDisk =
277 Fcb->Header.ValidDataLength.LowPart =
278 Fcb->Header.FileSize.LowPart;
279
280 if (CcIsFileCached(FileObject))
281 {
282 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
283 }
284 }
285 #endif
286 DPRINT1("Zeroing out data is not implemented\n");
287 }
288 }
289
290 /* Should the file be truncated on close? */
291 if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE))
292 {
293 if (Vcb->Condition == VcbGood)
294 {
295 // TODO: Actually truncate the file allocation
296 UNIMPLEMENTED;
297 }
298
299 /* Remove truncation flag */
300 Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
301 }
302
303 /* Check again if it should be deleted */
304 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
305 Fcb->Header.AllocationSize.LowPart == 0)
306 {
307 FatNotifyReportChange(IrpContext,
308 Vcb,
309 Fcb,
310 FILE_NOTIFY_CHANGE_FILE_NAME,
311 FILE_ACTION_REMOVED);
312 }
313
314 /* Remove the entry from the splay table if the file was deleted */
315 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE))
316 {
317 FatRemoveNames(IrpContext, Fcb);
318 }
319 }
320 }
321
322 ASSERT(Fcb->UncleanCount != 0);
323 Fcb->UncleanCount--;
324 if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
325 {
326 ASSERT(Fcb->NonCachedUncleanCount != 0);
327 Fcb->NonCachedUncleanCount--;
328 }
329
330 if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
331 (Fcb->NonCachedUncleanCount != 0) &&
332 (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
333 (Fcb->SectionObjectPointers.DataSectionObject != NULL))
334 {
335 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
336
337 /* Acquire and release PagingIo to get in sync with lazy writer */
338 ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
339 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
340
341 CcPurgeCacheSection(&Fcb->SectionObjectPointers,
342 NULL,
343 0,
344 FALSE);
345 }
346
347 if (Fcb->Condition == FcbBad)
348 {
349 //TruncateSize = &FatLargeZero;
350 UNIMPLEMENTED;
351 }
352
353 /* Cleanup the cache map */
354 CcUninitializeCacheMap(FileObject, TruncateSize, NULL);
355 break;
356
357 default:
358 KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
359 }
360
361 /* Cleanup the share access */
362
363 if (ShareAccess)
364 {
365 DPRINT("Cleaning up the share access\n");
366 IoRemoveShareAccess(FileObject, ShareAccess);
367 }
368
369 if (TypeOfOpen == UserFileOpen)
370 {
371 /* Update oplocks */
372 FsRtlCheckOplock(&Fcb->Fcb.Oplock,
373 Irp,
374 IrpContext,
375 NULL,
376 NULL);
377
378 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
379 }
380
381 /* Set the FO_CLEANUP_COMPLETE flag */
382 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
383
384 Status = STATUS_SUCCESS;
385
386 // TODO: Unpin repinned BCBs
387 //FatUnpinRepinnedBcbs(IrpContext);
388
389 /* Flush the volume if necessary */
390 if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
391 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
392 {
393 UNIMPLEMENTED;
394 }
395
396 /* Cleanup */
397 if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb);
398 if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb);
399
400 /* Send volume notification */
401 if (SendUnlockNotification)
402 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);
403
404 return Status;
405 }
406
407 NTSTATUS
408 NTAPI
409 FatCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
410 {
411 PFAT_IRP_CONTEXT IrpContext;
412 NTSTATUS Status;
413
414 DPRINT("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
415
416 /* FatCleanup works only with a volume device object */
417 if (DeviceObject == FatGlobalData.DiskDeviceObject)
418 {
419 /* Complete the request and return success */
420 Irp->IoStatus.Status = STATUS_SUCCESS;
421 Irp->IoStatus.Information = FILE_OPENED;
422
423 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
424
425 return STATUS_SUCCESS;
426 }
427
428 /* Enter FsRtl critical region */
429 FsRtlEnterFileSystem();
430
431 /* Build an irp context */
432 IrpContext = FatBuildIrpContext(Irp, TRUE);
433
434 /* Call internal function */
435 Status = FatiCleanup(IrpContext, Irp);
436
437 /* Leave FsRtl critical region */
438 FsRtlExitFileSystem();
439
440 return Status;
441 }
442
443 /* EOF */