Sync with trunk r58740.
[reactos.git] / drivers / filesystems / fastfat / blockdev.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/blockdev.c
5 * PURPOSE: Temporary sector reading support
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #define NDEBUG
13 #include "vfat.h"
14
15 /* FUNCTIONS ***************************************************************/
16
17 static IO_COMPLETION_ROUTINE VfatReadWritePartialCompletion;
18 static NTSTATUS NTAPI
19 VfatReadWritePartialCompletion (IN PDEVICE_OBJECT DeviceObject,
20 IN PIRP Irp,
21 IN PVOID Context)
22 {
23 PVFAT_IRP_CONTEXT IrpContext;
24 PMDL Mdl;
25
26 UNREFERENCED_PARAMETER(DeviceObject);
27
28 DPRINT("VfatReadWritePartialCompletion() called\n");
29
30 IrpContext = (PVFAT_IRP_CONTEXT)Context;
31
32 while ((Mdl = Irp->MdlAddress))
33 {
34 Irp->MdlAddress = Mdl->Next;
35 IoFreeMdl(Mdl);
36 }
37 if (Irp->PendingReturned)
38 {
39 IrpContext->Flags |= IRPCONTEXT_PENDINGRETURNED;
40 }
41 else
42 {
43 IrpContext->Flags &= ~IRPCONTEXT_PENDINGRETURNED;
44 }
45 if (!NT_SUCCESS(Irp->IoStatus.Status))
46 {
47 IrpContext->Irp->IoStatus.Status = Irp->IoStatus.Status;
48 }
49 if (0 == InterlockedDecrement((PLONG)&IrpContext->RefCount) &&
50 IrpContext->Flags & IRPCONTEXT_PENDINGRETURNED)
51 {
52 KeSetEvent(&IrpContext->Event, IO_NO_INCREMENT, FALSE);
53 }
54 IoFreeIrp(Irp);
55
56 DPRINT("VfatReadWritePartialCompletion() done\n");
57
58 return STATUS_MORE_PROCESSING_REQUIRED;
59 }
60
61 NTSTATUS
62 VfatReadDisk (IN PDEVICE_OBJECT pDeviceObject,
63 IN PLARGE_INTEGER ReadOffset,
64 IN ULONG ReadLength,
65 IN OUT PUCHAR Buffer,
66 IN BOOLEAN Override)
67 {
68 PIO_STACK_LOCATION Stack;
69 PIRP Irp;
70 IO_STATUS_BLOCK IoStatus;
71 KEVENT event;
72 NTSTATUS Status;
73
74 again:
75 KeInitializeEvent (&event, NotificationEvent, FALSE);
76
77 DPRINT ("VfatReadDisk(pDeviceObject %p, Offset %I64x, Length %d, Buffer %p)\n",
78 pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer);
79
80 DPRINT ("Building synchronous FSD Request...\n");
81 Irp = IoBuildSynchronousFsdRequest (IRP_MJ_READ,
82 pDeviceObject,
83 Buffer,
84 ReadLength,
85 ReadOffset,
86 &event,
87 &IoStatus);
88 if (Irp == NULL)
89 {
90 DPRINT("IoBuildSynchronousFsdRequest failed\n");
91 return(STATUS_UNSUCCESSFUL);
92 }
93
94 if (Override)
95 {
96 Stack = IoGetNextIrpStackLocation(Irp);
97 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
98 }
99
100 DPRINT ("Calling IO Driver... with irp %p\n", Irp);
101 Status = IoCallDriver (pDeviceObject, Irp);
102
103 DPRINT ("Waiting for IO Operation for %p\n", Irp);
104 if (Status == STATUS_PENDING)
105 {
106 DPRINT ("Operation pending\n");
107 KeWaitForSingleObject (&event, Suspended, KernelMode, FALSE, NULL);
108 DPRINT ("Getting IO Status... for %p\n", Irp);
109 Status = IoStatus.Status;
110 }
111
112 if (Status == STATUS_VERIFY_REQUIRED)
113 {
114 PDEVICE_OBJECT DeviceToVerify;
115
116 DPRINT1 ("Media change detected!\n");
117
118 /* Find the device to verify and reset the thread field to empty value again. */
119 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
120 IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
121 Status = IoVerifyVolume (DeviceToVerify,
122 FALSE);
123
124 if (NT_SUCCESS(Status))
125 {
126 DPRINT1 ("Volume verification successful; Reissuing read request\n");
127 goto again;
128 }
129 }
130
131 if (!NT_SUCCESS (Status))
132 {
133 DPRINT ("IO failed!!! VfatReadDisk : Error code: %x\n", Status);
134 DPRINT ("(pDeviceObject %p, Offset %I64x, Size %d, Buffer %p\n",
135 pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer);
136 return (Status);
137 }
138 DPRINT ("Block request succeeded for %p\n", Irp);
139 return (STATUS_SUCCESS);
140 }
141
142 NTSTATUS
143 VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
144 IN PLARGE_INTEGER ReadOffset,
145 IN ULONG ReadLength,
146 ULONG BufferOffset,
147 IN BOOLEAN Wait)
148 {
149 PIRP Irp;
150 PIO_STACK_LOCATION StackPtr;
151 NTSTATUS Status;
152 PVOID Buffer;
153
154 DPRINT ("VfatReadDiskPartial(IrpContext %p, ReadOffset %I64x, ReadLength %d, BufferOffset %x, Wait %d)\n",
155 IrpContext, ReadOffset->QuadPart, ReadLength, BufferOffset, Wait);
156
157 DPRINT ("Building asynchronous FSD Request...\n");
158
159 Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;
160
161 again:
162 Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE);
163 if (Irp == NULL)
164 {
165 DPRINT("IoAllocateIrp failed\n");
166 return(STATUS_UNSUCCESSFUL);
167 }
168
169 Irp->UserIosb = NULL;
170 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
171
172 StackPtr = IoGetNextIrpStackLocation(Irp);
173 StackPtr->MajorFunction = IRP_MJ_READ;
174 StackPtr->MinorFunction = 0;
175 StackPtr->Flags = 0;
176 StackPtr->Control = 0;
177 StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice;
178 StackPtr->FileObject = NULL;
179 StackPtr->CompletionRoutine = NULL;
180 StackPtr->Parameters.Read.Length = ReadLength;
181 StackPtr->Parameters.Read.ByteOffset = *ReadOffset;
182
183 if (!IoAllocateMdl(Buffer, ReadLength, FALSE, FALSE, Irp))
184 {
185 DPRINT("IoAllocateMdl failed\n");
186 IoFreeIrp(Irp);
187 return STATUS_UNSUCCESSFUL;
188 }
189
190 IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, ReadLength);
191
192 IoSetCompletionRoutine(Irp,
193 VfatReadWritePartialCompletion,
194 IrpContext,
195 TRUE,
196 TRUE,
197 TRUE);
198
199 if (Wait)
200 {
201 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
202 IrpContext->RefCount = 1;
203 }
204 else
205 {
206 InterlockedIncrement((PLONG)&IrpContext->RefCount);
207 }
208
209 DPRINT ("Calling IO Driver... with irp %p\n", Irp);
210 Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp);
211
212 if (Wait && Status == STATUS_PENDING)
213 {
214 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
215 Status = IrpContext->Irp->IoStatus.Status;
216 }
217
218 if (Status == STATUS_VERIFY_REQUIRED)
219 {
220 PDEVICE_OBJECT DeviceToVerify;
221
222 DPRINT1 ("Media change detected!\n");
223
224 /* Find the device to verify and reset the thread field to empty value again. */
225 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
226 IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
227 Status = IoVerifyVolume (DeviceToVerify,
228 FALSE);
229
230 if (NT_SUCCESS(Status))
231 {
232 DPRINT1 ("Volume verification successful; Reissuing read request\n");
233 goto again;
234 }
235 }
236
237 DPRINT("%x\n", Status);
238 return Status;
239 }
240
241
242 NTSTATUS
243 VfatWriteDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
244 IN PLARGE_INTEGER WriteOffset,
245 IN ULONG WriteLength,
246 IN ULONG BufferOffset,
247 IN BOOLEAN Wait)
248 {
249 PIRP Irp;
250 PIO_STACK_LOCATION StackPtr;
251 NTSTATUS Status;
252 PVOID Buffer;
253
254 DPRINT ("VfatWriteDiskPartial(IrpContext %p, WriteOffset %I64x, WriteLength %d, BufferOffset %x, Wait %d)\n",
255 IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait);
256
257 Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;
258
259 again:
260 DPRINT ("Building asynchronous FSD Request...\n");
261 Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE);
262 if (Irp == NULL)
263 {
264 DPRINT("IoAllocateIrp failed\n");
265 return(STATUS_UNSUCCESSFUL);
266 }
267
268 Irp->UserIosb = NULL;
269 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
270
271 StackPtr = IoGetNextIrpStackLocation(Irp);
272 StackPtr->MajorFunction = IRP_MJ_WRITE;
273 StackPtr->MinorFunction = 0;
274 StackPtr->Flags = 0;
275 StackPtr->Control = 0;
276 StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice;
277 StackPtr->FileObject = NULL;
278 StackPtr->CompletionRoutine = NULL;
279 StackPtr->Parameters.Read.Length = WriteLength;
280 StackPtr->Parameters.Read.ByteOffset = *WriteOffset;
281
282 if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp))
283 {
284 DPRINT("IoAllocateMdl failed\n");
285 IoFreeIrp(Irp);
286 return STATUS_UNSUCCESSFUL;
287 }
288 IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength);
289
290 IoSetCompletionRoutine(Irp,
291 VfatReadWritePartialCompletion,
292 IrpContext,
293 TRUE,
294 TRUE,
295 TRUE);
296
297 if (Wait)
298 {
299 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
300 IrpContext->RefCount = 1;
301 }
302 else
303 {
304 InterlockedIncrement((PLONG)&IrpContext->RefCount);
305 }
306
307
308 DPRINT ("Calling IO Driver...\n");
309 Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp);
310 if (Wait && Status == STATUS_PENDING)
311 {
312 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
313 Status = IrpContext->Irp->IoStatus.Status;
314 }
315
316 if (Status == STATUS_VERIFY_REQUIRED)
317 {
318 PDEVICE_OBJECT DeviceToVerify;
319
320 DPRINT1 ("Media change detected!\n");
321
322 /* Find the device to verify and reset the thread field to empty value again. */
323 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
324 IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
325 Status = IoVerifyVolume (DeviceToVerify,
326 FALSE);
327
328 if (NT_SUCCESS(Status))
329 {
330 DPRINT1 ("Volume verification successful; Reissuing write request\n");
331 goto again;
332 }
333 }
334
335 return Status;
336 }
337
338 NTSTATUS
339 VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject,
340 IN ULONG CtlCode,
341 IN PVOID InputBuffer OPTIONAL,
342 IN ULONG InputBufferSize,
343 IN OUT PVOID OutputBuffer OPTIONAL,
344 IN OUT PULONG OutputBufferSize,
345 IN BOOLEAN Override)
346 {
347 PIO_STACK_LOCATION Stack;
348 KEVENT Event;
349 PIRP Irp;
350 IO_STATUS_BLOCK IoStatus;
351 NTSTATUS Status;
352
353 DPRINT("VfatBlockDeviceIoControl(DeviceObject %p, CtlCode %x, "
354 "InputBuffer %p, InputBufferSize %x, OutputBuffer %p, "
355 "OutputBufferSize %p (%x)\n", DeviceObject, CtlCode,
356 InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize,
357 OutputBufferSize ? *OutputBufferSize : 0);
358
359 again:
360 KeInitializeEvent (&Event, NotificationEvent, FALSE);
361
362 DPRINT("Building device I/O control request ...\n");
363 Irp = IoBuildDeviceIoControlRequest(CtlCode,
364 DeviceObject,
365 InputBuffer,
366 InputBufferSize,
367 OutputBuffer,
368 (OutputBufferSize) ? *OutputBufferSize : 0,
369 FALSE,
370 &Event,
371 &IoStatus);
372 if (Irp == NULL)
373 {
374 DPRINT("IoBuildDeviceIoControlRequest failed\n");
375 return STATUS_INSUFFICIENT_RESOURCES;
376 }
377
378 if (Override)
379 {
380 Stack = IoGetNextIrpStackLocation(Irp);
381 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
382 }
383
384 DPRINT ("Calling IO Driver... with irp %p\n", Irp);
385 Status = IoCallDriver(DeviceObject, Irp);
386
387 DPRINT ("Waiting for IO Operation for %p\n", Irp);
388 if (Status == STATUS_PENDING)
389 {
390 DPRINT ("Operation pending\n");
391 KeWaitForSingleObject (&Event, Suspended, KernelMode, FALSE, NULL);
392 DPRINT ("Getting IO Status... for %p\n", Irp);
393
394 Status = IoStatus.Status;
395 }
396
397 if (Status == STATUS_VERIFY_REQUIRED)
398 {
399 PDEVICE_OBJECT DeviceToVerify;
400
401 DPRINT1 ("Media change detected!\n");
402
403 /* Find the device to verify and reset the thread field to empty value again. */
404 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
405 IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
406 Status = IoVerifyVolume (DeviceToVerify,
407 FALSE);
408
409 if (NT_SUCCESS(Status))
410 {
411 DPRINT1 ("Volume verification successful; Reissuing IOCTL request\n");
412 goto again;
413 }
414 }
415
416 if (OutputBufferSize)
417 {
418 *OutputBufferSize = IoStatus.Information;
419 }
420
421 DPRINT("Returning Status %x\n", Status);
422
423 return Status;
424 }