xref: /reactos/modules/rosapps/drivers/vfd/vfdrdwr.c (revision 02e84521)
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