xref: /reactos/drivers/filesystems/vfatfs/flush.c (revision 542e9f2b)
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