1 /*
2 * PROJECT: VFAT Filesystem
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Flushing routines
5 * COPYRIGHT: Copyright 2004-2013 Eric Kohl <eric.kohl@reactos.org>
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 static
19 NTSTATUS
VfatFlushFile(PDEVICE_EXTENSION DeviceExt,PVFATFCB Fcb)20 VfatFlushFile(
21 PDEVICE_EXTENSION DeviceExt,
22 PVFATFCB Fcb)
23 {
24 IO_STATUS_BLOCK IoStatus;
25 NTSTATUS Status;
26
27 DPRINT("VfatFlushFile(DeviceExt %p, Fcb %p) for '%wZ'\n", DeviceExt, Fcb, &Fcb->PathNameU);
28
29 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus);
30 if (IoStatus.Status == STATUS_INVALID_PARAMETER)
31 {
32 /* FIXME: Caching was possible not initialized */
33 IoStatus.Status = STATUS_SUCCESS;
34 }
35
36 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
37 if (BooleanFlagOn(Fcb->Flags, FCB_IS_DIRTY))
38 {
39 Status = VfatUpdateEntry(DeviceExt, Fcb);
40 if (!NT_SUCCESS(Status))
41 {
42 IoStatus.Status = Status;
43 }
44 }
45 ExReleaseResourceLite(&DeviceExt->DirResource);
46
47 return IoStatus.Status;
48 }
49
50 NTSTATUS
VfatFlushVolume(PDEVICE_EXTENSION DeviceExt,PVFATFCB VolumeFcb)51 VfatFlushVolume(
52 PDEVICE_EXTENSION DeviceExt,
53 PVFATFCB VolumeFcb)
54 {
55 PLIST_ENTRY ListEntry;
56 PVFATFCB Fcb;
57 NTSTATUS Status, ReturnStatus = STATUS_SUCCESS;
58 PIRP Irp;
59 KEVENT Event;
60 IO_STATUS_BLOCK IoStatusBlock;
61
62 DPRINT("VfatFlushVolume(DeviceExt %p, VolumeFcb %p)\n", DeviceExt, VolumeFcb);
63
64 ASSERT(VolumeFcb == DeviceExt->VolumeFcb);
65
66 ListEntry = DeviceExt->FcbListHead.Flink;
67 while (ListEntry != &DeviceExt->FcbListHead)
68 {
69 Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
70 ListEntry = ListEntry->Flink;
71 if (!vfatFCBIsDirectory(Fcb))
72 {
73 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
74 Status = VfatFlushFile(DeviceExt, Fcb);
75 ExReleaseResourceLite (&Fcb->MainResource);
76 if (!NT_SUCCESS(Status))
77 {
78 DPRINT1("VfatFlushFile failed, status = %x\n", Status);
79 ReturnStatus = Status;
80 }
81 }
82 /* FIXME: Stop flushing if this is a removable media and the media was removed */
83 }
84
85 ListEntry = DeviceExt->FcbListHead.Flink;
86 while (ListEntry != &DeviceExt->FcbListHead)
87 {
88 Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
89 ListEntry = ListEntry->Flink;
90 if (vfatFCBIsDirectory(Fcb))
91 {
92 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
93 Status = VfatFlushFile(DeviceExt, Fcb);
94 ExReleaseResourceLite (&Fcb->MainResource);
95 if (!NT_SUCCESS(Status))
96 {
97 DPRINT1("VfatFlushFile failed, status = %x\n", Status);
98 ReturnStatus = Status;
99 }
100 }
101 /* FIXME: Stop flushing if this is a removable media and the media was removed */
102 }
103
104 Fcb = (PVFATFCB) DeviceExt->FATFileObject->FsContext;
105
106 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
107 Status = VfatFlushFile(DeviceExt, Fcb);
108 ExReleaseResourceLite(&DeviceExt->FatResource);
109
110 /* Prepare an IRP to flush device buffers */
111 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
112 DeviceExt->StorageDevice,
113 NULL, 0, NULL, &Event,
114 &IoStatusBlock);
115 if (Irp != NULL)
116 {
117 KeInitializeEvent(&Event, NotificationEvent, FALSE);
118
119 Status = IoCallDriver(DeviceExt->StorageDevice, Irp);
120 if (Status == STATUS_PENDING)
121 {
122 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
123 Status = IoStatusBlock.Status;
124 }
125
126 /* Ignore device not supporting flush operation */
127 if (Status == STATUS_INVALID_DEVICE_REQUEST)
128 {
129 DPRINT1("Flush not supported, ignored\n");
130 Status = STATUS_SUCCESS;
131
132 }
133 }
134 else
135 {
136 Status = STATUS_INSUFFICIENT_RESOURCES;
137 }
138
139 if (!NT_SUCCESS(Status))
140 {
141 DPRINT1("VfatFlushFile failed, status = %x\n", Status);
142 ReturnStatus = Status;
143 }
144
145 return ReturnStatus;
146 }
147
148 NTSTATUS
VfatFlush(PVFAT_IRP_CONTEXT IrpContext)149 VfatFlush(
150 PVFAT_IRP_CONTEXT IrpContext)
151 {
152 NTSTATUS Status;
153 PVFATFCB Fcb;
154
155 /* This request is not allowed on the main device object. */
156 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
157 {
158 IrpContext->Irp->IoStatus.Information = 0;
159 return STATUS_INVALID_DEVICE_REQUEST;
160 }
161
162 Fcb = (PVFATFCB)IrpContext->FileObject->FsContext;
163 ASSERT(Fcb);
164
165 if (BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME))
166 {
167 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
168 Status = VfatFlushVolume(IrpContext->DeviceExt, Fcb);
169 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
170 }
171 else
172 {
173 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
174 Status = VfatFlushFile(IrpContext->DeviceExt, Fcb);
175 ExReleaseResourceLite (&Fcb->MainResource);
176 }
177
178 IrpContext->Irp->IoStatus.Information = 0;
179 return Status;
180 }
181
182 /* EOF */
183