1 /* 2 vfdrdwr.c 3 4 Virtual Floppy Drive for Windows NT platform 5 Kernel mode driver: Read and Write functions 6 7 Copyright (C) 2003-2005 Ken Kato 8 */ 9 10 #include "imports.h" 11 #include "vfddrv.h" 12 #include "vfddbg.h" 13 14 // 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 18 // 19 #define IO_READ_OFF(p) (p)->Parameters.Read.ByteOffset.QuadPart 20 #define IO_READ_LEN(p) (p)->Parameters.Read.Length 21 22 NTSTATUS 23 NTAPI 24 VfdReadWrite ( 25 IN PDEVICE_OBJECT DeviceObject, 26 IN PIRP Irp) 27 { 28 PDEVICE_EXTENSION device_extension; 29 PIO_STACK_LOCATION io_stack; 30 NTSTATUS status; 31 32 device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; 33 34 io_stack = IoGetCurrentIrpStackLocation(Irp); 35 36 #if DBG 37 if (DeviceObject && DeviceObject->DeviceExtension && 38 ((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) { 39 40 VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n", 41 GetMajorFuncName(io_stack->MajorFunction), 42 ((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer)); 43 } 44 else { 45 VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n", 46 GetMajorFuncName(io_stack->MajorFunction), 47 DeviceObject)); 48 } 49 #endif // DBG 50 51 #ifdef VFD_PNP 52 53 if (device_extension->DeviceState != VFD_WORKING) { 54 55 // Device is not yet started or being removed, reject any IO request 56 // TODO: Queue the IRPs 57 58 VFDTRACE(VFDWARN, ("[VFD] Device not ready\n")); 59 60 status = STATUS_INVALID_DEVICE_STATE; 61 goto complete_request; 62 } 63 else { 64 status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); 65 66 if (!NT_SUCCESS(status)) { 67 VFDTRACE(0, ("[VFD] Acquire RemoveLock failed: %s\n", GetStatusName(status))); 68 69 goto complete_request; 70 } 71 } 72 #endif // VFD_PNP 73 74 /* 75 // Check if volume verification is required 76 77 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) && 78 !(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) { 79 80 status = STATUS_VERIFY_REQUIRED; 81 goto complete_request; 82 } 83 */ 84 85 // Check if an image is opened 86 87 if (!device_extension->FileHandle && 88 !device_extension->FileBuffer) { 89 90 status = STATUS_NO_MEDIA_IN_DEVICE; 91 goto complete_request; 92 } 93 94 95 // Check if write operation is allowed 96 97 if (io_stack->MajorFunction == IRP_MJ_WRITE && 98 (device_extension->MediaFlags & VFD_FLAG_WRITE_PROTECTED)) { 99 100 status = STATUS_MEDIA_WRITE_PROTECTED; 101 goto complete_request; 102 } 103 104 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. 108 // 109 // Others are possible, but we don't check them since we trust the 110 // file system and they aren't deadly. 111 112 if ((IO_READ_OFF(io_stack) + IO_READ_LEN(io_stack)) > 113 VFD_SECTOR_TO_BYTE(device_extension->Sectors)) { 114 115 VFDTRACE(VFDWARN, 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))); 119 120 status = STATUS_INVALID_PARAMETER; 121 goto complete_request; 122 } 123 124 if (!VFD_SECTOR_ALIGNED((IO_READ_LEN(io_stack))) || 125 !VFD_SECTOR_ALIGNED((IO_READ_OFF(io_stack)))) { 126 127 VFDTRACE(VFDWARN, 128 ("[VFD] Invalid Alignment Offset:%I64u Length:%u\n", 129 IO_READ_OFF(io_stack), IO_READ_LEN(io_stack))); 130 131 status = STATUS_INVALID_PARAMETER; 132 goto complete_request; 133 } 134 135 // If read/write data length is 0, we are done 136 137 if (IO_READ_LEN(io_stack) == 0) { 138 status = STATUS_SUCCESS; 139 goto complete_request; 140 } 141 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 145 146 IoMarkIrpPending(Irp); 147 148 ExInterlockedInsertTailList( 149 &device_extension->ListHead, 150 &Irp->Tail.Overlay.ListEntry, 151 &device_extension->ListLock); 152 153 KeSetEvent( 154 &device_extension->RequestEvent, 155 (KPRIORITY) 0, 156 FALSE); 157 158 VFDTRACE(VFDINFO,("[VFD] %-40s - STATUS_PENDING\n", 159 GetMajorFuncName(io_stack->MajorFunction))); 160 161 return STATUS_PENDING; 162 163 complete_request: 164 165 // complete the request immediately 166 167 Irp->IoStatus.Status = status; 168 Irp->IoStatus.Information = 0; 169 IoCompleteRequest(Irp, IO_NO_INCREMENT); 170 171 VFDTRACE(VFDWARN,("[VFD] %-40s - %s\n", 172 GetMajorFuncName(io_stack->MajorFunction), 173 GetStatusName(status))); 174 175 return status; 176 } 177 178 // 179 // Substitute for MmGetSystemAddressForMdlSafe 180 // for NT 4.0 DDK does not provide its equivqlent 181 // originally written by Bruce Engle for filedisk 182 // 183 static PVOID 184 MmGetSystemAddressForMdlPrettySafe( 185 IN PMDL Mdl, 186 IN MM_PAGE_PRIORITY Priority) 187 { 188 #if (VER_PRODUCTBUILD >= 2195) 189 if (OsMajorVersion >= 5) { 190 return MmGetSystemAddressForMdlSafe(Mdl, Priority); 191 } 192 else { 193 #endif // (VER_PRODUCTBUILD >= 2195) 194 CSHORT MdlMappingCanFail; 195 PVOID MappedSystemVa; 196 197 MdlMappingCanFail = (CSHORT)(Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL); 198 199 Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL; 200 201 MappedSystemVa = MmGetSystemAddressForMdl(Mdl); 202 203 if (!MdlMappingCanFail) { 204 Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL; 205 } 206 207 return MappedSystemVa; 208 #if (VER_PRODUCTBUILD >= 2195) 209 } 210 #endif // (VER_PRODUCTBUILD >= 2195) 211 } 212 213 // 214 // Read sectors from image file or RAM disk buffer into read buffer 215 // 216 VOID 217 VfdReadData( 218 IN PDEVICE_EXTENSION DeviceExtension, 219 IN OUT PIRP Irp, 220 IN ULONG Length, 221 IN PLARGE_INTEGER Offset) 222 { 223 PVOID buf; 224 225 VFDTRACE(VFDINFO,("[VFD] VfdReadData - IN\n")); 226 227 buf = MmGetSystemAddressForMdlPrettySafe( 228 Irp->MdlAddress, NormalPagePriority); 229 230 if (!buf) { 231 VFDTRACE(0, 232 ("[VFD] MmGetSystemAddressForMdlPrettySafe\n")); 233 234 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 235 return; 236 } 237 238 if (DeviceExtension->FileHandle) { 239 240 // Read from image file 241 Irp->IoStatus.Status = ZwReadFile( 242 DeviceExtension->FileHandle, 243 NULL, 244 NULL, 245 NULL, 246 &Irp->IoStatus, 247 buf, 248 Length, 249 Offset, 250 NULL); 251 252 if (NT_SUCCESS(Irp->IoStatus.Status)) { 253 Irp->IoStatus.Information = Length; 254 } 255 else { 256 VFDTRACE(0, 257 ("[VFD] ZwReadFile - %s\n", 258 GetStatusName(Irp->IoStatus.Status))); 259 } 260 } 261 else if (DeviceExtension->FileBuffer) { 262 263 // Copy from RAM disk buffer 264 RtlMoveMemory( 265 buf, 266 DeviceExtension->FileBuffer + Offset->QuadPart, 267 Length); 268 269 Irp->IoStatus.Status = STATUS_SUCCESS; 270 Irp->IoStatus.Information = Length; 271 } 272 else { 273 // no image opened 274 Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE; 275 } 276 277 VFDTRACE(VFDINFO,("[VFD] VfdReadData - %s\n", 278 GetStatusName(Irp->IoStatus.Status))); 279 280 return; 281 } 282 283 // 284 // Write sectors from write buffer into image file or RAM image buffer 285 // 286 VOID 287 VfdWriteData( 288 IN PDEVICE_EXTENSION DeviceExtension, 289 IN OUT PIRP Irp, 290 IN ULONG Length, 291 IN PLARGE_INTEGER Offset) 292 { 293 PVOID buf; 294 295 VFDTRACE(VFDINFO,("[VFD] VfdWriteData - IN\n")); 296 297 buf = MmGetSystemAddressForMdlPrettySafe( 298 Irp->MdlAddress, NormalPagePriority); 299 300 if (!buf) { 301 VFDTRACE(0, 302 ("[VFD] MmGetSystemAddressForMdlPrettySafe\n")); 303 304 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 305 return; 306 } 307 308 if (DeviceExtension->FileHandle) { 309 310 // Write into image file 311 Irp->IoStatus.Status = ZwWriteFile( 312 DeviceExtension->FileHandle, 313 NULL, 314 NULL, 315 NULL, 316 &Irp->IoStatus, 317 buf, 318 Length, 319 Offset, 320 NULL); 321 322 if (NT_SUCCESS(Irp->IoStatus.Status)) { 323 Irp->IoStatus.Information = Length; 324 } 325 else { 326 VFDTRACE(0, 327 ("[VFD] ZwWriteFile - %s\n", 328 GetStatusName(Irp->IoStatus.Status))); 329 } 330 } 331 else if (DeviceExtension->FileBuffer) { 332 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; 338 } 339 340 // Copy into RAM image buffer 341 RtlMoveMemory( 342 DeviceExtension->FileBuffer + Offset->QuadPart, 343 buf, Length); 344 345 Irp->IoStatus.Status = STATUS_SUCCESS; 346 Irp->IoStatus.Information = Length; 347 } 348 else { 349 // no image opened 350 Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE; 351 } 352 353 VFDTRACE(VFDINFO,("[VFD] VfdWriteData - %s\n", 354 GetStatusName(Irp->IoStatus.Status))); 355 356 return; 357 } 358