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