4 Virtual Floppy Drive for Windows NT platform
5 Kernel mode driver: Read and Write functions
7 Copyright (C) 2003-2005 Ken Kato
15 // IRP_MJ_READ and IRP_MJ_WRITE dispatcher
16 // Insert the IRP into the IRP queue list.
17 // Actual operation is performed by the device thread
19 #define IO_READ_OFF(p) (p)->Parameters.Read.ByteOffset.QuadPart
20 #define IO_READ_LEN(p) (p)->Parameters.Read.Length
25 IN PDEVICE_OBJECT DeviceObject
,
28 PDEVICE_EXTENSION device_extension
;
29 PIO_STACK_LOCATION io_stack
;
32 device_extension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
34 io_stack
= IoGetCurrentIrpStackLocation(Irp
);
37 if (DeviceObject
&& DeviceObject
->DeviceExtension
&&
38 ((PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->DeviceName
.Buffer
) {
40 VFDTRACE(VFDINFO
, ("[VFD] %-40s %ws\n",
41 GetMajorFuncName(io_stack
->MajorFunction
),
42 ((PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->DeviceName
.Buffer
));
45 VFDTRACE(VFDINFO
, ("[VFD] %-40s %p\n",
46 GetMajorFuncName(io_stack
->MajorFunction
),
53 if (device_extension
->DeviceState
!= VFD_WORKING
) {
55 // Device is not yet started or being removed, reject any IO request
56 // TODO: Queue the IRPs
58 VFDTRACE(VFDWARN
, ("[VFD] Device not ready\n"));
60 status
= STATUS_INVALID_DEVICE_STATE
;
61 goto complete_request
;
64 status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
66 if (!NT_SUCCESS(status
)) {
67 VFDTRACE(0, ("[VFD] Acquire RemoveLock failed: %s\n", GetStatusName(status
)));
69 goto complete_request
;
75 // Check if volume verification is required
77 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
78 !(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
80 status = STATUS_VERIFY_REQUIRED;
81 goto complete_request;
85 // Check if an image is opened
87 if (!device_extension
->FileHandle
&&
88 !device_extension
->FileBuffer
) {
90 status
= STATUS_NO_MEDIA_IN_DEVICE
;
91 goto complete_request
;
95 // Check if write operation is allowed
97 if (io_stack
->MajorFunction
== IRP_MJ_WRITE
&&
98 (device_extension
->MediaFlags
& VFD_FLAG_WRITE_PROTECTED
)) {
100 status
= STATUS_MEDIA_WRITE_PROTECTED
;
101 goto complete_request
;
105 // Check for invalid parameters. It is an error for the starting offset
106 // + length to go past the end of the partition, or for the length or
107 // offset to not be a proper multiple of the sector size.
109 // Others are possible, but we don't check them since we trust the
110 // file system and they aren't deadly.
112 if ((IO_READ_OFF(io_stack
) + IO_READ_LEN(io_stack
)) >
113 VFD_SECTOR_TO_BYTE(device_extension
->Sectors
)) {
116 ("[VFD] Offset:%I64u + Length:%u goes past the media size %lu\n",
117 IO_READ_OFF(io_stack
), IO_READ_LEN(io_stack
),
118 VFD_SECTOR_TO_BYTE(device_extension
->Sectors
)));
120 status
= STATUS_INVALID_PARAMETER
;
121 goto complete_request
;
124 if (!VFD_SECTOR_ALIGNED((IO_READ_LEN(io_stack
))) ||
125 !VFD_SECTOR_ALIGNED((IO_READ_OFF(io_stack
)))) {
128 ("[VFD] Invalid Alignment Offset:%I64u Length:%u\n",
129 IO_READ_OFF(io_stack
), IO_READ_LEN(io_stack
)));
131 status
= STATUS_INVALID_PARAMETER
;
132 goto complete_request
;
135 // If read/write data length is 0, we are done
137 if (IO_READ_LEN(io_stack
) == 0) {
138 status
= STATUS_SUCCESS
;
139 goto complete_request
;
142 // It seems that actual read/write operation is going to take place
143 // so mark the IRP as pending, insert the IRP into queue list
144 // then signal the device thread to perform the operation
146 IoMarkIrpPending(Irp
);
148 ExInterlockedInsertTailList(
149 &device_extension
->ListHead
,
150 &Irp
->Tail
.Overlay
.ListEntry
,
151 &device_extension
->ListLock
);
154 &device_extension
->RequestEvent
,
158 VFDTRACE(VFDINFO
,("[VFD] %-40s - STATUS_PENDING\n",
159 GetMajorFuncName(io_stack
->MajorFunction
)));
161 return STATUS_PENDING
;
165 // complete the request immediately
167 Irp
->IoStatus
.Status
= status
;
168 Irp
->IoStatus
.Information
= 0;
169 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
171 VFDTRACE(VFDWARN
,("[VFD] %-40s - %s\n",
172 GetMajorFuncName(io_stack
->MajorFunction
),
173 GetStatusName(status
)));
179 // Substitute for MmGetSystemAddressForMdlSafe
180 // for NT 4.0 DDK does not provide its equivqlent
181 // originally written by Bruce Engle for filedisk
184 MmGetSystemAddressForMdlPrettySafe(
186 IN MM_PAGE_PRIORITY Priority
)
188 #if (VER_PRODUCTBUILD >= 2195)
189 if (OsMajorVersion
>= 5) {
190 return MmGetSystemAddressForMdlSafe(Mdl
, Priority
);
193 #endif // (VER_PRODUCTBUILD >= 2195)
194 CSHORT MdlMappingCanFail
;
195 PVOID MappedSystemVa
;
197 MdlMappingCanFail
= (CSHORT
)(Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
);
199 Mdl
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
201 MappedSystemVa
= MmGetSystemAddressForMdl(Mdl
);
203 if (!MdlMappingCanFail
) {
204 Mdl
->MdlFlags
&= ~MDL_MAPPING_CAN_FAIL
;
207 return MappedSystemVa
;
208 #if (VER_PRODUCTBUILD >= 2195)
210 #endif // (VER_PRODUCTBUILD >= 2195)
214 // Read sectors from image file or RAM disk buffer into read buffer
218 IN PDEVICE_EXTENSION DeviceExtension
,
221 IN PLARGE_INTEGER Offset
)
225 VFDTRACE(VFDINFO
,("[VFD] VfdReadData - IN\n"));
227 buf
= MmGetSystemAddressForMdlPrettySafe(
228 Irp
->MdlAddress
, NormalPagePriority
);
232 ("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
234 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
238 if (DeviceExtension
->FileHandle
) {
240 // Read from image file
241 Irp
->IoStatus
.Status
= ZwReadFile(
242 DeviceExtension
->FileHandle
,
252 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
253 Irp
->IoStatus
.Information
= Length
;
257 ("[VFD] ZwReadFile - %s\n",
258 GetStatusName(Irp
->IoStatus
.Status
)));
261 else if (DeviceExtension
->FileBuffer
) {
263 // Copy from RAM disk buffer
266 DeviceExtension
->FileBuffer
+ Offset
->QuadPart
,
269 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
270 Irp
->IoStatus
.Information
= Length
;
274 Irp
->IoStatus
.Status
= STATUS_NO_MEDIA_IN_DEVICE
;
277 VFDTRACE(VFDINFO
,("[VFD] VfdReadData - %s\n",
278 GetStatusName(Irp
->IoStatus
.Status
)));
284 // Write sectors from write buffer into image file or RAM image buffer
288 IN PDEVICE_EXTENSION DeviceExtension
,
291 IN PLARGE_INTEGER Offset
)
295 VFDTRACE(VFDINFO
,("[VFD] VfdWriteData - IN\n"));
297 buf
= MmGetSystemAddressForMdlPrettySafe(
298 Irp
->MdlAddress
, NormalPagePriority
);
302 ("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
304 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
308 if (DeviceExtension
->FileHandle
) {
310 // Write into image file
311 Irp
->IoStatus
.Status
= ZwWriteFile(
312 DeviceExtension
->FileHandle
,
322 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
323 Irp
->IoStatus
.Information
= Length
;
327 ("[VFD] ZwWriteFile - %s\n",
328 GetStatusName(Irp
->IoStatus
.Status
)));
331 else if (DeviceExtension
->FileBuffer
) {
333 // Deal with the modify flag
334 if (RtlCompareMemory(
335 DeviceExtension
->FileBuffer
+ Offset
->QuadPart
,
336 buf
, Length
) != Length
) {
337 DeviceExtension
->MediaFlags
|= VFD_FLAG_DATA_MODIFIED
;
340 // Copy into RAM image buffer
342 DeviceExtension
->FileBuffer
+ Offset
->QuadPart
,
345 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
346 Irp
->IoStatus
.Information
= Length
;
350 Irp
->IoStatus
.Status
= STATUS_NO_MEDIA_IN_DEVICE
;
353 VFDTRACE(VFDINFO
,("[VFD] VfdWriteData - %s\n",
354 GetStatusName(Irp
->IoStatus
.Status
)));