[FFS] Don't leak on failure
[reactos.git] / drivers / filesystems / ffs / src / block.c
1 /*
2 * FFS File System Driver for Windows
3 *
4 * block.c
5 *
6 * 2004.5.6 ~
7 *
8 * Lee Jae-Hong, http://www.pyrasis.com
9 *
10 * See License.txt
11 *
12 */
13
14 #include "ntifs.h"
15 #include "ffsdrv.h"
16
17 /* Globals */
18
19 extern PFFS_GLOBAL FFSGlobal;
20
21
22 /* Definitions */
23
24 typedef struct _FFS_RW_CONTEXT {
25 PIRP MasterIrp;
26 KEVENT Event;
27 BOOLEAN Wait;
28 LONG Blocks;
29 ULONG Length;
30 } FFS_RW_CONTEXT, *PFFS_RW_CONTEXT;
31
32 #ifdef _PREFAST_
33 IO_COMPLETION_ROUTINE FFSReadWriteBlockSyncCompletionRoutine;
34 IO_COMPLETION_ROUTINE FFSReadWriteBlockAsyncCompletionRoutine;
35 IO_COMPLETION_ROUTINE FFSMediaEjectControlCompletion;
36 #endif // _PREFAST_
37
38 NTSTATUS NTAPI
39 FFSReadWriteBlockSyncCompletionRoutine(
40 IN PDEVICE_OBJECT DeviceObject,
41 IN PIRP Irp,
42 IN PVOID Context);
43
44 NTSTATUS NTAPI
45 FFSReadWriteBlockAsyncCompletionRoutine(
46 IN PDEVICE_OBJECT DeviceObject,
47 IN PIRP Irp,
48 IN PVOID Context);
49
50 NTSTATUS NTAPI
51 FFSMediaEjectControlCompletion(
52 IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp,
54 IN PVOID Contxt);
55
56
57 #ifdef ALLOC_PRAGMA
58 #pragma alloc_text(PAGE, FFSLockUserBuffer)
59 #pragma alloc_text(PAGE, FFSGetUserBuffer)
60 #pragma alloc_text(PAGE, FFSReadSync)
61 #pragma alloc_text(PAGE, FFSReadDisk)
62 #pragma alloc_text(PAGE, FFSDiskIoControl)
63 #pragma alloc_text(PAGE, FFSReadWriteBlocks)
64 #pragma alloc_text(PAGE, FFSMediaEjectControl)
65 #pragma alloc_text(PAGE, FFSDiskShutDown)
66 #endif
67
68
69 NTSTATUS
70 FFSLockUserBuffer(
71 IN PIRP Irp,
72 IN ULONG Length,
73 IN LOCK_OPERATION Operation)
74 {
75 NTSTATUS Status;
76
77 PAGED_CODE();
78
79 ASSERT(Irp != NULL);
80
81 if (Irp->MdlAddress != NULL)
82 {
83 return STATUS_SUCCESS;
84 }
85
86 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
87
88 if (Irp->MdlAddress == NULL)
89 {
90 return STATUS_INSUFFICIENT_RESOURCES;
91 }
92
93 _SEH2_TRY
94 {
95 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
96
97 Status = STATUS_SUCCESS;
98 }
99 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
100 {
101 IoFreeMdl(Irp->MdlAddress);
102
103 Irp->MdlAddress = NULL;
104
105 FFSBreakPoint();
106
107 Status = STATUS_INVALID_USER_BUFFER;
108 } _SEH2_END;
109
110 return Status;
111 }
112
113
114 PVOID
115 FFSGetUserBuffer(
116 IN PIRP Irp)
117 {
118 PAGED_CODE();
119
120 ASSERT(Irp != NULL);
121
122 if (Irp->MdlAddress)
123 {
124 #if (_WIN32_WINNT >= 0x0500)
125 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
126 #else
127 return MmGetSystemAddressForMdl(Irp->MdlAddress);
128 #endif
129 }
130 else
131 {
132 return Irp->UserBuffer;
133 }
134 }
135
136
137 NTSTATUS NTAPI
138 FFSReadWriteBlockSyncCompletionRoutine(
139 IN PDEVICE_OBJECT DeviceObject,
140 IN PIRP Irp,
141 IN PVOID Context)
142 {
143 PFFS_RW_CONTEXT pContext = (PFFS_RW_CONTEXT)Context;
144
145 if (!NT_SUCCESS(Irp->IoStatus.Status))
146 {
147
148 pContext->MasterIrp->IoStatus = Irp->IoStatus;
149 }
150
151 IoFreeMdl(Irp->MdlAddress);
152 IoFreeIrp(Irp);
153
154 if (InterlockedDecrement(&pContext->Blocks) == 0)
155 {
156 pContext->MasterIrp->IoStatus.Information = 0;
157
158 if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status))
159 {
160 pContext->MasterIrp->IoStatus.Information =
161 pContext->Length;
162 }
163
164 KeSetEvent(&pContext->Event, 0, FALSE);
165 }
166
167 UNREFERENCED_PARAMETER(DeviceObject);
168
169 return STATUS_MORE_PROCESSING_REQUIRED;
170 }
171
172 NTSTATUS NTAPI
173 FFSReadWriteBlockAsyncCompletionRoutine(
174 IN PDEVICE_OBJECT DeviceObject,
175 IN PIRP Irp,
176 IN PVOID Context)
177 {
178 PFFS_RW_CONTEXT pContext = (PFFS_RW_CONTEXT)Context;
179
180 if (!NT_SUCCESS(Irp->IoStatus.Status))
181 {
182 pContext->MasterIrp->IoStatus = Irp->IoStatus;
183 }
184
185 if (InterlockedDecrement(&pContext->Blocks) == 0)
186 {
187 pContext->MasterIrp->IoStatus.Information = 0;
188
189 if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status))
190 {
191 pContext->MasterIrp->IoStatus.Information =
192 pContext->Length;
193 }
194
195 IoMarkIrpPending(pContext->MasterIrp);
196
197 ExFreePool(pContext);
198 }
199
200 UNREFERENCED_PARAMETER(DeviceObject);
201
202 return STATUS_SUCCESS;
203
204 }
205
206 NTSTATUS
207 FFSReadWriteBlocks(
208 IN PFFS_IRP_CONTEXT IrpContext,
209 IN PFFS_VCB Vcb,
210 IN PFFS_BDL FFSBDL,
211 IN ULONG Length,
212 IN ULONG Count,
213 IN BOOLEAN bVerify)
214 {
215 PMDL Mdl;
216 PIRP Irp;
217 PIRP MasterIrp = IrpContext->Irp;
218 PIO_STACK_LOCATION IrpSp;
219 NTSTATUS Status = STATUS_SUCCESS;
220 PFFS_RW_CONTEXT pContext = NULL;
221 ULONG i;
222 BOOLEAN bBugCheck = FALSE;
223
224 PAGED_CODE();
225
226 ASSERT(MasterIrp);
227
228 _SEH2_TRY
229 {
230
231 pContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(FFS_RW_CONTEXT), FFS_POOL_TAG);
232
233 if (!pContext)
234 {
235 Status = STATUS_INSUFFICIENT_RESOURCES;
236 _SEH2_LEAVE;
237 }
238
239 RtlZeroMemory(pContext, sizeof(FFS_RW_CONTEXT));
240
241 pContext->Wait = IrpContext->IsSynchronous;
242 pContext->MasterIrp = MasterIrp;
243 pContext->Blocks = Count;
244 pContext->Length = 0;
245
246 if (pContext->Wait)
247 {
248 KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE);
249 }
250
251 for (i = 0; i < Count; i++)
252 {
253
254 Irp = IoMakeAssociatedIrp(MasterIrp,
255 (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1));
256 if (!Irp)
257 {
258 #ifdef __REACTOS__
259 ExFreePoolWithTag(pContext, FFS_POOL_TAG);
260 pContext = NULL;
261 #endif
262 Status = STATUS_INSUFFICIENT_RESOURCES;
263 _SEH2_LEAVE;
264 }
265
266 Mdl = IoAllocateMdl((PCHAR)MasterIrp->UserBuffer +
267 FFSBDL[i].Offset,
268 FFSBDL[i].Length,
269 FALSE,
270 FALSE,
271 Irp);
272
273 if (!Mdl)
274 {
275 #ifdef __REACTOS__
276 ExFreePoolWithTag(pContext, FFS_POOL_TAG);
277 pContext = NULL;
278 #endif
279 Status = STATUS_INSUFFICIENT_RESOURCES;
280 _SEH2_LEAVE;
281 }
282
283 IoBuildPartialMdl(MasterIrp->MdlAddress,
284 Mdl,
285 (PCHAR)MasterIrp->UserBuffer + FFSBDL[i].Offset,
286 FFSBDL[i].Length);
287
288 IoSetNextIrpStackLocation(Irp);
289 IrpSp = IoGetCurrentIrpStackLocation(Irp);
290
291
292 IrpSp->MajorFunction = IrpContext->MajorFunction;
293 IrpSp->Parameters.Read.Length = FFSBDL[i].Length;
294 IrpSp->Parameters.Read.ByteOffset.QuadPart = FFSBDL[i].Lba;
295
296 IoSetCompletionRoutine(Irp,
297 IrpContext->IsSynchronous ?
298 &FFSReadWriteBlockSyncCompletionRoutine :
299 &FFSReadWriteBlockAsyncCompletionRoutine,
300 (PVOID) pContext,
301 TRUE,
302 TRUE,
303 TRUE);
304
305 IrpSp = IoGetNextIrpStackLocation(Irp);
306
307 IrpSp->MajorFunction = IrpContext->MajorFunction;
308 IrpSp->Parameters.Read.Length = FFSBDL[i].Length;
309 IrpSp->Parameters.Read.ByteOffset.QuadPart = FFSBDL[i].Lba;
310
311 if (bVerify)
312 {
313 SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
314 }
315
316 FFSBDL[i].Irp = Irp;
317 }
318
319 MasterIrp->AssociatedIrp.IrpCount = Count;
320
321 if (IrpContext->IsSynchronous)
322 {
323 MasterIrp->AssociatedIrp.IrpCount += 1;
324 }
325
326 pContext->Length = Length;
327
328 bBugCheck = TRUE;
329
330 for (i = 0; i < Count; i++)
331 {
332 Status = IoCallDriver(Vcb->TargetDeviceObject,
333 FFSBDL[i].Irp);
334 }
335
336 if (IrpContext->IsSynchronous)
337 {
338 KeWaitForSingleObject(&(pContext->Event),
339 Executive, KernelMode, FALSE, NULL);
340
341 KeClearEvent(&(pContext->Event));
342 }
343 }
344
345 _SEH2_FINALLY
346 {
347 if (IrpContext->IsSynchronous)
348 {
349 if (MasterIrp)
350 Status = MasterIrp->IoStatus.Status;
351
352 if (pContext)
353 ExFreePool(pContext);
354
355 }
356 else
357 {
358 IrpContext->Irp = NULL;
359 Status = STATUS_PENDING;
360 }
361
362 if (_SEH2_AbnormalTermination())
363 {
364 if (bBugCheck)
365 {
366 FFSBugCheck(FFS_BUGCHK_BLOCK, 0, 0, 0);
367 }
368
369 for (i = 0; i < Count; i++)
370 {
371 if (FFSBDL[i].Irp != NULL)
372 {
373 if (FFSBDL[i].Irp->MdlAddress != NULL)
374 {
375 IoFreeMdl(FFSBDL[i].Irp->MdlAddress);
376 }
377
378 IoFreeIrp(FFSBDL[i].Irp);
379 }
380 }
381 }
382 } _SEH2_END;
383
384 return Status;
385 }
386
387
388 NTSTATUS
389 FFSReadSync(
390 IN PFFS_VCB Vcb,
391 IN ULONGLONG Offset,
392 IN ULONG Length,
393 OUT PVOID Buffer,
394 IN BOOLEAN bVerify)
395 {
396 KEVENT Event;
397 PIRP Irp;
398 IO_STATUS_BLOCK IoStatus;
399 NTSTATUS Status;
400
401 PAGED_CODE();
402
403 ASSERT(Vcb != NULL);
404 ASSERT(Vcb->TargetDeviceObject != NULL);
405 ASSERT(Buffer != NULL);
406
407 KeInitializeEvent(&Event, NotificationEvent, FALSE);
408
409 Irp = IoBuildSynchronousFsdRequest(
410 IRP_MJ_READ,
411 Vcb->TargetDeviceObject,
412 Buffer,
413 Length,
414 (PLARGE_INTEGER)(&Offset),
415 &Event,
416 &IoStatus);
417
418 if (!Irp)
419 {
420 return STATUS_INSUFFICIENT_RESOURCES;
421 }
422
423 if (bVerify)
424 {
425 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags,
426 SL_OVERRIDE_VERIFY_VOLUME);
427 }
428
429 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
430
431 if (Status == STATUS_PENDING)
432 {
433 KeWaitForSingleObject(
434 &Event,
435 Suspended,
436 KernelMode,
437 FALSE,
438 NULL);
439
440 Status = IoStatus.Status;
441 }
442
443 return Status;
444 }
445
446
447 NTSTATUS
448 FFSReadDisk(
449 IN PFFS_VCB Vcb,
450 IN ULONGLONG Offset,
451 IN ULONG Size,
452 IN PVOID Buffer,
453 IN BOOLEAN bVerify)
454 {
455 NTSTATUS Status;
456 PUCHAR Buf;
457 ULONG Length;
458 ULONGLONG Lba;
459
460 PAGED_CODE();
461
462 Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
463 Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) &
464 (~((ULONG)SECTOR_SIZE - 1));
465
466 Buf = ExAllocatePoolWithTag(PagedPool, Length, FFS_POOL_TAG);
467 if (!Buf)
468 {
469 FFSPrint((DBG_ERROR, "FFSReadDisk: no enough memory.\n"));
470 Status = STATUS_INSUFFICIENT_RESOURCES;
471
472 goto errorout;
473 }
474
475 Status = FFSReadSync(Vcb,
476 Lba,
477 Length,
478 Buf,
479 FALSE);
480
481 if (!NT_SUCCESS(Status))
482 {
483 FFSPrint((DBG_ERROR, "FFSReadDisk: Read Block Device error.\n"));
484
485 goto errorout;
486 }
487
488 RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size);
489
490 errorout:
491
492 if (Buf)
493 ExFreePool(Buf);
494
495 return Status;
496 }
497
498
499 NTSTATUS
500 FFSDiskIoControl(
501 IN PDEVICE_OBJECT DeviceObject,
502 IN ULONG IoctlCode,
503 IN PVOID InputBuffer,
504 IN ULONG InputBufferSize,
505 IN OUT PVOID OutputBuffer,
506 IN OUT PULONG OutputBufferSize)
507 {
508 ULONG OutBufferSize = 0;
509 KEVENT Event;
510 PIRP Irp;
511 IO_STATUS_BLOCK IoStatus;
512 NTSTATUS Status;
513
514 PAGED_CODE();
515
516 ASSERT(DeviceObject != NULL);
517
518 if (OutputBufferSize)
519 {
520 OutBufferSize = *OutputBufferSize;
521 }
522
523 KeInitializeEvent(&Event, NotificationEvent, FALSE);
524
525 Irp = IoBuildDeviceIoControlRequest(
526 IoctlCode,
527 DeviceObject,
528 InputBuffer,
529 InputBufferSize,
530 OutputBuffer,
531 OutBufferSize,
532 FALSE,
533 &Event,
534 &IoStatus);
535
536 if (Irp == NULL)
537 {
538 FFSPrint((DBG_ERROR, "FFSDiskIoControl: Building IRQ error!\n"));
539 return STATUS_INSUFFICIENT_RESOURCES;
540 }
541
542 Status = IoCallDriver(DeviceObject, Irp);
543
544 if (Status == STATUS_PENDING)
545 {
546 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
547 Status = IoStatus.Status;
548 }
549
550 if (OutputBufferSize)
551 {
552 *OutputBufferSize = (ULONG) IoStatus.Information;
553 }
554
555 return Status;
556 }
557
558
559 NTSTATUS NTAPI
560 FFSMediaEjectControlCompletion(
561 IN PDEVICE_OBJECT DeviceObject,
562 IN PIRP Irp,
563 IN PVOID Contxt)
564 {
565 PKEVENT Event = (PKEVENT)Contxt;
566
567 KeSetEvent(Event, 0, FALSE);
568
569 UNREFERENCED_PARAMETER(DeviceObject);
570
571 return STATUS_SUCCESS;
572 }
573
574
575 __drv_mustHoldCriticalRegion
576 VOID
577 FFSMediaEjectControl(
578 IN PFFS_IRP_CONTEXT IrpContext,
579 IN PFFS_VCB Vcb,
580 IN BOOLEAN bPrevent)
581 {
582 PIRP Irp;
583 KEVENT Event;
584 NTSTATUS Status;
585 PREVENT_MEDIA_REMOVAL Prevent;
586 IO_STATUS_BLOCK IoStatus;
587
588 PAGED_CODE();
589
590 ExAcquireResourceExclusiveLite(
591 &Vcb->MainResource,
592 TRUE);
593
594 if (bPrevent != IsFlagOn(Vcb->Flags, VCB_REMOVAL_PREVENTED))
595 {
596 if (bPrevent)
597 {
598 SetFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
599 }
600 else
601 {
602 ClearFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
603 }
604 }
605
606 ExReleaseResourceForThreadLite(
607 &Vcb->MainResource,
608 ExGetCurrentResourceThread());
609
610 Prevent.PreventMediaRemoval = bPrevent;
611
612 KeInitializeEvent(&Event, NotificationEvent, FALSE);
613
614 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_MEDIA_REMOVAL,
615 Vcb->TargetDeviceObject,
616 &Prevent,
617 sizeof(PREVENT_MEDIA_REMOVAL),
618 NULL,
619 0,
620 FALSE,
621 NULL,
622 &IoStatus);
623
624 if (Irp != NULL)
625 {
626 IoSetCompletionRoutine(Irp,
627 FFSMediaEjectControlCompletion,
628 &Event,
629 TRUE,
630 TRUE,
631 TRUE);
632
633 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
634
635 if (Status == STATUS_PENDING)
636 {
637 Status = KeWaitForSingleObject(&Event,
638 Executive,
639 KernelMode,
640 FALSE,
641 NULL);
642 }
643 }
644 }
645
646
647 NTSTATUS
648 FFSDiskShutDown(
649 PFFS_VCB Vcb)
650 {
651 PIRP Irp;
652 KEVENT Event;
653 NTSTATUS Status;
654 IO_STATUS_BLOCK IoStatus;
655
656 PAGED_CODE();
657
658 KeInitializeEvent(&Event, NotificationEvent, FALSE);
659
660 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
661 Vcb->TargetDeviceObject,
662 NULL,
663 0,
664 NULL,
665 &Event,
666 &IoStatus);
667
668 if (Irp)
669 {
670 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
671
672 if (Status == STATUS_PENDING)
673 {
674 KeWaitForSingleObject(&Event,
675 Executive,
676 KernelMode,
677 FALSE,
678 NULL);
679
680 Status = IoStatus.Status;
681 }
682 }
683 else
684 {
685 Status = IoStatus.Status;
686 }
687
688 return Status;
689 }