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 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 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 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