[NTFS]
[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 Status = STATUS_INSUFFICIENT_RESOURCES;
259 _SEH2_LEAVE;
260 }
261
262 Mdl = IoAllocateMdl((PCHAR)MasterIrp->UserBuffer +
263 FFSBDL[i].Offset,
264 FFSBDL[i].Length,
265 FALSE,
266 FALSE,
267 Irp);
268
269 if (!Mdl)
270 {
271 Status = STATUS_INSUFFICIENT_RESOURCES;
272 _SEH2_LEAVE;
273 }
274
275 IoBuildPartialMdl(MasterIrp->MdlAddress,
276 Mdl,
277 (PCHAR)MasterIrp->UserBuffer + FFSBDL[i].Offset,
278 FFSBDL[i].Length);
279
280 IoSetNextIrpStackLocation(Irp);
281 IrpSp = IoGetCurrentIrpStackLocation(Irp);
282
283
284 IrpSp->MajorFunction = IrpContext->MajorFunction;
285 IrpSp->Parameters.Read.Length = FFSBDL[i].Length;
286 IrpSp->Parameters.Read.ByteOffset.QuadPart = FFSBDL[i].Lba;
287
288 IoSetCompletionRoutine(Irp,
289 IrpContext->IsSynchronous ?
290 &FFSReadWriteBlockSyncCompletionRoutine :
291 &FFSReadWriteBlockAsyncCompletionRoutine,
292 (PVOID) pContext,
293 TRUE,
294 TRUE,
295 TRUE);
296
297 IrpSp = IoGetNextIrpStackLocation(Irp);
298
299 IrpSp->MajorFunction = IrpContext->MajorFunction;
300 IrpSp->Parameters.Read.Length = FFSBDL[i].Length;
301 IrpSp->Parameters.Read.ByteOffset.QuadPart = FFSBDL[i].Lba;
302
303 if (bVerify)
304 {
305 SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
306 }
307
308 FFSBDL[i].Irp = Irp;
309 }
310
311 MasterIrp->AssociatedIrp.IrpCount = Count;
312
313 if (IrpContext->IsSynchronous)
314 {
315 MasterIrp->AssociatedIrp.IrpCount += 1;
316 }
317
318 pContext->Length = Length;
319
320 bBugCheck = TRUE;
321
322 for (i = 0; i < Count; i++)
323 {
324 Status = IoCallDriver(Vcb->TargetDeviceObject,
325 FFSBDL[i].Irp);
326 }
327
328 if (IrpContext->IsSynchronous)
329 {
330 KeWaitForSingleObject(&(pContext->Event),
331 Executive, KernelMode, FALSE, NULL);
332
333 KeClearEvent(&(pContext->Event));
334 }
335 }
336
337 _SEH2_FINALLY
338 {
339 if (IrpContext->IsSynchronous)
340 {
341 if (MasterIrp)
342 Status = MasterIrp->IoStatus.Status;
343
344 if (pContext)
345 ExFreePool(pContext);
346
347 }
348 else
349 {
350 IrpContext->Irp = NULL;
351 Status = STATUS_PENDING;
352 }
353
354 if (_SEH2_AbnormalTermination())
355 {
356 if (bBugCheck)
357 {
358 FFSBugCheck(FFS_BUGCHK_BLOCK, 0, 0, 0);
359 }
360
361 for (i = 0; i < Count; i++)
362 {
363 if (FFSBDL[i].Irp != NULL)
364 {
365 if (FFSBDL[i].Irp->MdlAddress != NULL)
366 {
367 IoFreeMdl(FFSBDL[i].Irp->MdlAddress);
368 }
369
370 IoFreeIrp(FFSBDL[i].Irp);
371 }
372 }
373 }
374 } _SEH2_END;
375
376 return Status;
377 }
378
379
380 NTSTATUS
381 FFSReadSync(
382 IN PFFS_VCB Vcb,
383 IN ULONGLONG Offset,
384 IN ULONG Length,
385 OUT PVOID Buffer,
386 IN BOOLEAN bVerify)
387 {
388 KEVENT Event;
389 PIRP Irp;
390 IO_STATUS_BLOCK IoStatus;
391 NTSTATUS Status;
392
393 PAGED_CODE();
394
395 ASSERT(Vcb != NULL);
396 ASSERT(Vcb->TargetDeviceObject != NULL);
397 ASSERT(Buffer != NULL);
398
399 KeInitializeEvent(&Event, NotificationEvent, FALSE);
400
401 Irp = IoBuildSynchronousFsdRequest(
402 IRP_MJ_READ,
403 Vcb->TargetDeviceObject,
404 Buffer,
405 Length,
406 (PLARGE_INTEGER)(&Offset),
407 &Event,
408 &IoStatus);
409
410 if (!Irp)
411 {
412 return STATUS_INSUFFICIENT_RESOURCES;
413 }
414
415 if (bVerify)
416 {
417 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags,
418 SL_OVERRIDE_VERIFY_VOLUME);
419 }
420
421 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
422
423 if (Status == STATUS_PENDING)
424 {
425 KeWaitForSingleObject(
426 &Event,
427 Suspended,
428 KernelMode,
429 FALSE,
430 NULL);
431
432 Status = IoStatus.Status;
433 }
434
435 return Status;
436 }
437
438
439 NTSTATUS
440 FFSReadDisk(
441 IN PFFS_VCB Vcb,
442 IN ULONGLONG Offset,
443 IN ULONG Size,
444 IN PVOID Buffer,
445 IN BOOLEAN bVerify)
446 {
447 NTSTATUS Status;
448 PUCHAR Buf;
449 ULONG Length;
450 ULONGLONG Lba;
451
452 PAGED_CODE();
453
454 Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
455 Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) &
456 (~((ULONG)SECTOR_SIZE - 1));
457
458 Buf = ExAllocatePoolWithTag(PagedPool, Length, FFS_POOL_TAG);
459 if (!Buf)
460 {
461 FFSPrint((DBG_ERROR, "FFSReadDisk: no enough memory.\n"));
462 Status = STATUS_INSUFFICIENT_RESOURCES;
463
464 goto errorout;
465 }
466
467 Status = FFSReadSync(Vcb,
468 Lba,
469 Length,
470 Buf,
471 FALSE);
472
473 if (!NT_SUCCESS(Status))
474 {
475 FFSPrint((DBG_ERROR, "FFSReadDisk: Read Block Device error.\n"));
476
477 goto errorout;
478 }
479
480 RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size);
481
482 errorout:
483
484 if (Buf)
485 ExFreePool(Buf);
486
487 return Status;
488 }
489
490
491 NTSTATUS
492 FFSDiskIoControl(
493 IN PDEVICE_OBJECT DeviceObject,
494 IN ULONG IoctlCode,
495 IN PVOID InputBuffer,
496 IN ULONG InputBufferSize,
497 IN OUT PVOID OutputBuffer,
498 IN OUT PULONG OutputBufferSize)
499 {
500 ULONG OutBufferSize = 0;
501 KEVENT Event;
502 PIRP Irp;
503 IO_STATUS_BLOCK IoStatus;
504 NTSTATUS Status;
505
506 PAGED_CODE();
507
508 ASSERT(DeviceObject != NULL);
509
510 if (OutputBufferSize)
511 {
512 OutBufferSize = *OutputBufferSize;
513 }
514
515 KeInitializeEvent(&Event, NotificationEvent, FALSE);
516
517 Irp = IoBuildDeviceIoControlRequest(
518 IoctlCode,
519 DeviceObject,
520 InputBuffer,
521 InputBufferSize,
522 OutputBuffer,
523 OutBufferSize,
524 FALSE,
525 &Event,
526 &IoStatus);
527
528 if (Irp == NULL)
529 {
530 FFSPrint((DBG_ERROR, "FFSDiskIoControl: Building IRQ error!\n"));
531 return STATUS_INSUFFICIENT_RESOURCES;
532 }
533
534 Status = IoCallDriver(DeviceObject, Irp);
535
536 if (Status == STATUS_PENDING)
537 {
538 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
539 Status = IoStatus.Status;
540 }
541
542 if (OutputBufferSize)
543 {
544 *OutputBufferSize = (ULONG) IoStatus.Information;
545 }
546
547 return Status;
548 }
549
550
551 NTSTATUS NTAPI
552 FFSMediaEjectControlCompletion(
553 IN PDEVICE_OBJECT DeviceObject,
554 IN PIRP Irp,
555 IN PVOID Contxt)
556 {
557 PKEVENT Event = (PKEVENT)Contxt;
558
559 KeSetEvent(Event, 0, FALSE);
560
561 UNREFERENCED_PARAMETER(DeviceObject);
562
563 return STATUS_SUCCESS;
564 }
565
566
567 __drv_mustHoldCriticalRegion
568 VOID
569 FFSMediaEjectControl(
570 IN PFFS_IRP_CONTEXT IrpContext,
571 IN PFFS_VCB Vcb,
572 IN BOOLEAN bPrevent)
573 {
574 PIRP Irp;
575 KEVENT Event;
576 NTSTATUS Status;
577 PREVENT_MEDIA_REMOVAL Prevent;
578 IO_STATUS_BLOCK IoStatus;
579
580 PAGED_CODE();
581
582 ExAcquireResourceExclusiveLite(
583 &Vcb->MainResource,
584 TRUE);
585
586 if (bPrevent != IsFlagOn(Vcb->Flags, VCB_REMOVAL_PREVENTED))
587 {
588 if (bPrevent)
589 {
590 SetFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
591 }
592 else
593 {
594 ClearFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
595 }
596 }
597
598 ExReleaseResourceForThreadLite(
599 &Vcb->MainResource,
600 ExGetCurrentResourceThread());
601
602 Prevent.PreventMediaRemoval = bPrevent;
603
604 KeInitializeEvent(&Event, NotificationEvent, FALSE);
605
606 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_MEDIA_REMOVAL,
607 Vcb->TargetDeviceObject,
608 &Prevent,
609 sizeof(PREVENT_MEDIA_REMOVAL),
610 NULL,
611 0,
612 FALSE,
613 NULL,
614 &IoStatus);
615
616 if (Irp != NULL)
617 {
618 IoSetCompletionRoutine(Irp,
619 FFSMediaEjectControlCompletion,
620 &Event,
621 TRUE,
622 TRUE,
623 TRUE);
624
625 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
626
627 if (Status == STATUS_PENDING)
628 {
629 Status = KeWaitForSingleObject(&Event,
630 Executive,
631 KernelMode,
632 FALSE,
633 NULL);
634 }
635 }
636 }
637
638
639 NTSTATUS
640 FFSDiskShutDown(
641 PFFS_VCB Vcb)
642 {
643 PIRP Irp;
644 KEVENT Event;
645 NTSTATUS Status;
646 IO_STATUS_BLOCK IoStatus;
647
648 PAGED_CODE();
649
650 KeInitializeEvent(&Event, NotificationEvent, FALSE);
651
652 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
653 Vcb->TargetDeviceObject,
654 NULL,
655 0,
656 NULL,
657 &Event,
658 &IoStatus);
659
660 if (Irp)
661 {
662 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
663
664 if (Status == STATUS_PENDING)
665 {
666 KeWaitForSingleObject(&Event,
667 Executive,
668 KernelMode,
669 FALSE,
670 NULL);
671
672 Status = IoStatus.Status;
673 }
674 }
675 else
676 {
677 Status = IoStatus.Status;
678 }
679
680 return Status;
681 }