[FASTFAT_NEW]
[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 }
226
227 /* Unlock all file locks */
228 FsRtlFastUnlockAll(&Fcb->Fcb.Lock,
229 FileObject,
230 IoGetRequestorProcess(Irp),
231 NULL);
232
233 if (Vcb->Condition == VcbGood)
234 {
235 if (Fcb->Condition != FcbBad)
236 {
237 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
238 // TODO: Update on-disk structures
239 }
240
241 if (Fcb->UncleanCount == 1 &&
242 Fcb->Condition != FcbBad)
243 {
244 //DELETE_CONTEXT DeleteContext;
245
246 /* Should this file be deleted on close? */
247 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
248 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
249 {
250 UNIMPLEMENTED;
251 }
252 else
253 {
254 if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
255 (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart))
256 {
257 #if 0
258 ULONG ValidDataLength;
259
260 ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
261
262 if (ValidDataLength < Fcb->ValidDataToDisk) {
263 ValidDataLength = Fcb->ValidDataToDisk;
264 }
265
266 if (ValidDataLength < Fcb->Header.FileSize.LowPart)
267 {
268 FatZeroData( IrpContext,
269 Vcb,
270 FileObject,
271 ValidDataLength,
272 Fcb->Header.FileSize.LowPart -
273 ValidDataLength );
274
275 Fcb->ValidDataToDisk =
276 Fcb->Header.ValidDataLength.LowPart =
277 Fcb->Header.FileSize.LowPart;
278
279 if (CcIsFileCached(FileObject))
280 {
281 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
282 }
283 }
284 #endif
285 DPRINT1("Zeroing out data is not implemented\n");
286 }
287 }
288
289 /* Should the file be truncated on close? */
290 if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE))
291 {
292 if (Vcb->Condition == VcbGood)
293 {
294 // TODO: Actually truncate the file allocation
295 UNIMPLEMENTED;
296 }
297
298 /* Remove truncation flag */
299 Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
300 }
301
302 /* Check again if it should be deleted */
303 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
304 Fcb->Header.AllocationSize.LowPart == 0)
305 {
306 FatNotifyReportChange(IrpContext,
307 Vcb,
308 Fcb,
309 FILE_NOTIFY_CHANGE_FILE_NAME,
310 FILE_ACTION_REMOVED);
311 }
312
313 /* Remove the entry from the splay table if the file was deleted */
314 if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE))
315 {
316 FatRemoveNames(IrpContext, Fcb);
317 }
318 }
319 }
320
321 ASSERT(Fcb->UncleanCount != 0);
322 Fcb->UncleanCount--;
323 if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
324 {
325 ASSERT(Fcb->NonCachedUncleanCount != 0);
326 Fcb->NonCachedUncleanCount--;
327 }
328
329 if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
330 (Fcb->NonCachedUncleanCount != 0) &&
331 (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
332 (Fcb->SectionObjectPointers.DataSectionObject != NULL))
333 {
334 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
335
336 /* Acquire and release PagingIo to get in sync with lazy writer */
337 ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
338 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
339
340 CcPurgeCacheSection(&Fcb->SectionObjectPointers,
341 NULL,
342 0,
343 FALSE);
344 }
345
346 if (Fcb->Condition == FcbBad)
347 {
348 //TruncateSize = &FatLargeZero;
349 UNIMPLEMENTED;
350 }
351
352 /* Cleanup the cache map */
353 CcUninitializeCacheMap(FileObject, TruncateSize, NULL);
354 break;
355
356 default:
357 KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
358 }
359
360 /* Cleanup the share access */
361
362 if (ShareAccess)
363 {
364 DPRINT("Cleaning up the share access\n");
365 IoRemoveShareAccess(FileObject, ShareAccess);
366 }
367
368 if (TypeOfOpen == UserFileOpen)
369 {
370 /* Update oplocks */
371 FsRtlCheckOplock(&Fcb->Fcb.Oplock,
372 Irp,
373 IrpContext,
374 NULL,
375 NULL);
376
377 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
378 }
379
380 /* Set the FO_CLEANUP_COMPLETE flag */
381 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
382
383 Status = STATUS_SUCCESS;
384
385 // TODO: Unpin repinned BCBs
386 //FatUnpinRepinnedBcbs(IrpContext);
387
388 /* Flush the volume if necessary */
389 if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
390 !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
391 {
392 UNIMPLEMENTED;
393 }
394
395 /* Cleanup */
396 if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb);
397 if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb);
398
399 /* Send volume notification */
400 if (SendUnlockNotification)
401 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);
402
403 return Status;
404 }
405
406 NTSTATUS
407 NTAPI
408 FatCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
409 {
410 PFAT_IRP_CONTEXT IrpContext;
411 NTSTATUS Status;
412
413 DPRINT("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
414
415 /* FatCleanup works only with a volume device object */
416 if (DeviceObject == FatGlobalData.DiskDeviceObject)
417 {
418 /* Complete the request and return success */
419 Irp->IoStatus.Status = STATUS_SUCCESS;
420 Irp->IoStatus.Information = FILE_OPENED;
421
422 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
423
424 return STATUS_SUCCESS;
425 }
426
427 /* Enter FsRtl critical region */
428 FsRtlEnterFileSystem();
429
430 /* Build an irp context */
431 IrpContext = FatBuildIrpContext(Irp, TRUE);
432
433 /* Call internal function */
434 Status = FatiCleanup(IrpContext, Irp);
435
436 /* Leave FsRtl critical region */
437 FsRtlExitFileSystem();
438
439 return Status;
440 }
441
442 /* EOF */