d6cb8d71176c493e4cf6941e58648a45ee1c0370
[reactos.git] / reactos / drivers / filesystems / ext2 / src / fsctl.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: fsctl.c
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "ext2fs.h"
13
14 /* GLOBALS ***************************************************************/
15
16 extern PEXT2_GLOBAL Ext2Global;
17
18 /* DEFINITIONS *************************************************************/
19
20 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2IsHandleCountZero)
22 #pragma alloc_text(PAGE, Ext2LockVcb)
23 #pragma alloc_text(PAGE, Ext2LockVolume)
24 #pragma alloc_text(PAGE, Ext2UnlockVcb)
25 #pragma alloc_text(PAGE, Ext2UnlockVolume)
26 #pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo)
27 #pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase)
28 #pragma alloc_text(PAGE, Ext2QueryExtentMappings)
29 #pragma alloc_text(PAGE, Ext2QueryRetrievalPointers)
30 #pragma alloc_text(PAGE, Ext2GetRetrievalPointers)
31 #pragma alloc_text(PAGE, Ext2UserFsRequest)
32 #pragma alloc_text(PAGE, Ext2IsMediaWriteProtected)
33 #pragma alloc_text(PAGE, Ext2MountVolume)
34 #pragma alloc_text(PAGE, Ext2PurgeVolume)
35 #pragma alloc_text(PAGE, Ext2PurgeFile)
36 #pragma alloc_text(PAGE, Ext2DismountVolume)
37 #pragma alloc_text(PAGE, Ext2IsVolumeMounted)
38 #pragma alloc_text(PAGE, Ext2VerifyVolume)
39 #pragma alloc_text(PAGE, Ext2FileSystemControl)
40 #endif
41
42
43 VOID
44 Ext2SetVpbFlag (
45 IN PVPB Vpb,
46 IN USHORT Flag )
47 {
48 KIRQL OldIrql;
49
50 IoAcquireVpbSpinLock(&OldIrql);
51 Vpb->Flags |= Flag;
52 IoReleaseVpbSpinLock(OldIrql);
53 }
54
55 VOID
56 Ext2ClearVpbFlag (
57 IN PVPB Vpb,
58 IN USHORT Flag )
59 {
60 KIRQL OldIrql;
61
62 IoAcquireVpbSpinLock(&OldIrql);
63 Vpb->Flags &= ~Flag;
64 IoReleaseVpbSpinLock(OldIrql);
65 }
66
67 BOOLEAN
68 Ext2IsHandleCountZero(IN PEXT2_VCB Vcb)
69 {
70 PEXT2_FCB Fcb;
71 PLIST_ENTRY List;
72
73 for ( List = Vcb->FcbList.Flink;
74 List != &Vcb->FcbList;
75 List = List->Flink ) {
76
77 Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next);
78
79 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
80 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
81
82 DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n",
83 Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount));
84
85 if (Fcb->OpenHandleCount) {
86 return FALSE;
87 }
88 }
89
90 return TRUE;
91 }
92
93 NTSTATUS
94 Ext2LockVcb (IN PEXT2_VCB Vcb,
95 IN PFILE_OBJECT FileObject)
96 {
97 NTSTATUS Status = STATUS_SUCCESS;
98
99 _SEH2_TRY {
100
101 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
102 DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n"));
103 Status = STATUS_ACCESS_DENIED;
104 _SEH2_LEAVE;
105 }
106
107 if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) {
108 DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n"));
109
110 Status = STATUS_ACCESS_DENIED;
111 _SEH2_LEAVE;
112 }
113
114 if (!Ext2IsHandleCountZero(Vcb)) {
115 DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n"));
116
117 Status = STATUS_ACCESS_DENIED;
118 _SEH2_LEAVE;
119 }
120
121 SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
122 Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED);
123 Vcb->LockFile = FileObject;
124
125 DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n"));
126
127 } _SEH2_FINALLY {
128 // Nothing
129 } _SEH2_END;
130
131 return Status;
132 }
133
134
135 NTSTATUS
136 Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
137 {
138 PIO_STACK_LOCATION IrpSp;
139 PDEVICE_OBJECT DeviceObject;
140 PEXT2_VCB Vcb;
141 NTSTATUS Status;
142 BOOLEAN VcbResourceAcquired = FALSE;
143
144 _SEH2_TRY {
145
146 ASSERT(IrpContext != NULL);
147
148 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
149 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
150
151 DeviceObject = IrpContext->DeviceObject;
152
153 Status = STATUS_UNSUCCESSFUL;
154
155 //
156 // This request is not allowed on the main device object
157 //
158 if (IsExt2FsDevice(DeviceObject)) {
159 Status = STATUS_INVALID_PARAMETER;
160 _SEH2_LEAVE;
161 }
162
163 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
164
165 ASSERT(Vcb != NULL);
166
167 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
168 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
169
170 ASSERT(IsMounted(Vcb));
171
172 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
173
174 #if (_WIN32_WINNT >= 0x0500)
175 CcWaitForCurrentLazyWriterActivity();
176 #endif
177 ExAcquireResourceExclusiveLite(
178 &Vcb->MainResource,
179 TRUE );
180
181 VcbResourceAcquired = TRUE;
182
183 /* flush dirty data before locking the volume */
184 if (!IsVcbReadOnly(Vcb)) {
185 Ext2FlushFiles(IrpContext, Vcb, FALSE);
186 Ext2FlushVolume(IrpContext, Vcb, FALSE);
187 }
188
189 Status = Ext2LockVcb(Vcb, IrpSp->FileObject);
190
191 } _SEH2_FINALLY {
192
193 if (VcbResourceAcquired) {
194 ExReleaseResourceLite(&Vcb->MainResource);
195 }
196
197 if (!IrpContext->ExceptionInProgress) {
198 Ext2CompleteIrpContext(IrpContext, Status);
199 }
200 } _SEH2_END;
201
202 return Status;
203 }
204
205 NTSTATUS
206 Ext2UnlockVcb ( IN PEXT2_VCB Vcb,
207 IN PFILE_OBJECT FileObject )
208 {
209 NTSTATUS Status;
210
211 _SEH2_TRY {
212
213 if (FileObject && FileObject->FsContext != Vcb) {
214 Status = STATUS_NOT_LOCKED;
215 _SEH2_LEAVE;
216 }
217
218 if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
219 DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n"));
220 Status = STATUS_NOT_LOCKED;
221 _SEH2_LEAVE;
222 }
223
224 if (Vcb->LockFile == FileObject) {
225 ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
226 Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
227 DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n"));
228 Status = STATUS_SUCCESS;
229 } else {
230 Status = STATUS_NOT_LOCKED;
231 }
232
233 } _SEH2_FINALLY {
234 // Nothing
235 } _SEH2_END;
236
237 return Status;
238 }
239
240 NTSTATUS
241 Ext2UnlockVolume (
242 IN PEXT2_IRP_CONTEXT IrpContext
243 )
244 {
245 PIO_STACK_LOCATION IrpSp;
246 PDEVICE_OBJECT DeviceObject;
247 NTSTATUS Status;
248 PEXT2_VCB Vcb;
249 BOOLEAN VcbResourceAcquired = FALSE;
250
251 _SEH2_TRY {
252
253 ASSERT(IrpContext != NULL);
254 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
255 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
256
257 DeviceObject = IrpContext->DeviceObject;
258 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
259
260 //
261 // This request is not allowed on the main device object
262 //
263 if (IsExt2FsDevice(DeviceObject)) {
264 Status = STATUS_INVALID_PARAMETER;
265 _SEH2_LEAVE;
266 }
267
268 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
269 ASSERT(Vcb != NULL);
270 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
271 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
272
273 ExAcquireResourceExclusiveLite(
274 &Vcb->MainResource,
275 TRUE );
276 VcbResourceAcquired = TRUE;
277
278 Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject);
279
280 } _SEH2_FINALLY {
281
282 if (VcbResourceAcquired) {
283 ExReleaseResourceLite(&Vcb->MainResource);
284 }
285
286 if (!IrpContext->ExceptionInProgress) {
287 Ext2CompleteIrpContext(IrpContext, Status);
288 }
289 } _SEH2_END;
290
291 return Status;
292 }
293
294
295 NTSTATUS
296 Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext )
297 {
298 NTSTATUS Status;
299 PIRP Irp;
300 PIO_STACK_LOCATION IrpSp;
301
302 #ifndef __REACTOS__
303 PVPB NewVpb = NULL;
304 #endif
305 HANDLE Handle;
306 PLIST_ENTRY ListEntry;
307
308 ULONG InputLength = 0;
309 PFILE_OBJECT FileObject;
310 PDEVICE_OBJECT DeviceObject;
311 BOOLEAN GlobalResourceAcquired = FALSE;
312
313 LUID Privilege = {SE_TCB_PRIVILEGE, 0};
314
315 _SEH2_TRY {
316
317 Irp = IrpContext->Irp;
318 IrpSp = IoGetCurrentIrpStackLocation(Irp);
319
320 if (!IsExt2FsDevice(IrpSp->DeviceObject)) {
321 Status = STATUS_INVALID_DEVICE_REQUEST;
322 _SEH2_LEAVE;
323 }
324
325 if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
326 Status = STATUS_PRIVILEGE_NOT_HELD;
327 _SEH2_LEAVE;
328 }
329
330
331 #ifndef _GNU_NTIFS_
332 InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
333 #else
334 InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
335 Parameters.FileSystemControl.InputBufferLength;
336 #endif
337
338 #if defined(_WIN64)
339 if (IoIs32bitProcess(Irp)) {
340 if (InputLength != sizeof(UINT32)) {
341 Status = STATUS_INVALID_PARAMETER;
342 _SEH2_LEAVE;
343 }
344 Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
345 } else
346 #endif
347 {
348 if (InputLength != sizeof(HANDLE)) {
349 Status = STATUS_INVALID_PARAMETER;
350 _SEH2_LEAVE;
351 }
352 Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
353 }
354
355 Status = ObReferenceObjectByHandle( Handle,
356 0,
357 *IoFileObjectType,
358 KernelMode,
359 (void **)&FileObject,
360 NULL );
361
362 if (!NT_SUCCESS(Status)) {
363 _SEH2_LEAVE;
364 } else {
365 DeviceObject = FileObject->DeviceObject;
366 ObDereferenceObject(FileObject);
367 }
368
369 ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
370 GlobalResourceAcquired = TRUE;
371
372 ListEntry = Ext2Global->VcbList.Flink;
373 while (ListEntry != &Ext2Global->VcbList) {
374
375 PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
376 ListEntry = ListEntry->Flink;
377
378 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh "
379 "Blink = %p &Vcb->Next = %p\n",
380 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
381
382 if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) {
383
384 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh "
385 "Blink = %p &Vcb->Next = %p\n",
386 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
387 /* dismount the volume */
388 Ext2CheckDismount(IrpContext, Vcb, FALSE);
389 }
390 }
391
392 } _SEH2_FINALLY {
393
394 if (GlobalResourceAcquired) {
395 ExReleaseResourceLite(&Ext2Global->Resource);
396 }
397
398 if (!IrpContext->ExceptionInProgress) {
399 Ext2CompleteIrpContext(IrpContext, Status);
400 }
401 } _SEH2_END;
402
403 return Status;
404 }
405
406 NTSTATUS
407 Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext)
408 {
409 PIO_STACK_LOCATION IrpSp;
410 PEXT2_VCB Vcb;
411 PEXT2_CCB Ccb;
412 NTSTATUS status;
413
414 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
415
416 Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
417 Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2;
418
419 ASSERT(Vcb != NULL);
420
421 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
422 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
423
424 ASSERT(IsMounted(Vcb));
425
426 if (Ccb) {
427 SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
428 status = STATUS_SUCCESS;
429 } else {
430 status = STATUS_INVALID_PARAMETER;
431 }
432
433 Ext2CompleteIrpContext(IrpContext, status);
434 return status;
435 }
436
437 /*
438 * Ext2OplockRequest
439 *
440 * oplock requests handler routine
441 *
442 * Arguments:
443 * IrpContext: the ext2 irp context
444 *
445 * Return Value:
446 * NTSTATUS: The return status for the operation
447 *
448 */
449
450 NTSTATUS
451 Ext2OplockRequest (
452 IN PEXT2_IRP_CONTEXT IrpContext
453 )
454 {
455 NTSTATUS Status;
456
457 ULONG FsCtrlCode;
458 PDEVICE_OBJECT DeviceObject;
459 PFILE_OBJECT FileObject;
460
461 PIRP Irp = NULL;
462 PIO_STACK_LOCATION IrpSp;
463 PEXTENDED_IO_STACK_LOCATION EIrpSp;
464
465 PEXT2_VCB Vcb = NULL;
466 PEXT2_FCB Fcb = NULL;
467 PEXT2_CCB Ccb = NULL;
468
469 ULONG OplockCount = 0;
470
471 BOOLEAN VcbResourceAcquired = FALSE;
472 BOOLEAN FcbResourceAcquired = FALSE;
473
474 ASSERT(IrpContext);
475
476 _SEH2_TRY {
477
478 Irp = IrpContext->Irp;
479 ASSERT(Irp);
480
481 IrpSp = IoGetCurrentIrpStackLocation(Irp);
482 ASSERT(IrpSp);
483 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
484
485 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
486 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
487
488 DeviceObject = IrpContext->DeviceObject;
489
490 //
491 // This request is not allowed on the main device object
492 //
493 if (IsExt2FsDevice(DeviceObject)) {
494 Status = STATUS_INVALID_DEVICE_REQUEST;
495 _SEH2_LEAVE;
496 }
497
498 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
499
500 ASSERT(Vcb != NULL);
501
502 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
503 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
504
505 ASSERT(IsMounted(Vcb));
506
507 FileObject = IrpContext->FileObject;
508
509 Fcb = (PEXT2_FCB) FileObject->FsContext;
510
511 //
512 // This request is not allowed on volumes
513 //
514
515 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
516 Status = STATUS_INVALID_PARAMETER;
517 _SEH2_LEAVE;
518 }
519
520 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
521 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
522
523 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
524 Status = STATUS_FILE_DELETED;
525 _SEH2_LEAVE;
526 }
527
528 Ccb = (PEXT2_CCB) FileObject->FsContext2;
529 if (Ccb == NULL) {
530 Status = STATUS_INVALID_PARAMETER;
531 _SEH2_LEAVE;
532 }
533
534
535 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
536 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
537
538 FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode;
539
540 switch (FsCtrlCode) {
541
542 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
543 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
544 case FSCTL_REQUEST_BATCH_OPLOCK:
545
546 VcbResourceAcquired =
547 ExAcquireResourceSharedLite(
548 &Vcb->MainResource,
549 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
550
551 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
552
553 FcbResourceAcquired =
554 ExAcquireResourceExclusiveLite (
555 &Fcb->MainResource,
556 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
557
558 if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
559 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor);
560 } else {
561 OplockCount = Fcb->OpenHandleCount;
562 }
563
564 break;
565
566 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
567 case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
568 case FSCTL_OPLOCK_BREAK_NOTIFY:
569 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
570
571 FcbResourceAcquired =
572 ExAcquireResourceSharedLite (
573 &Fcb->MainResource,
574 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
575
576 break;
577
578 default:
579
580 Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0);
581 }
582
583
584 //
585 // Call the FsRtl routine to grant/acknowledge oplock.
586 //
587
588 Status = FsRtlOplockFsctrl( &Fcb->Oplock,
589 Irp,
590 OplockCount );
591
592 //
593 // Set the flag indicating if Fast I/O is possible
594 //
595
596 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
597 IrpContext->Irp = NULL;
598
599 } _SEH2_FINALLY {
600
601 if (FcbResourceAcquired) {
602 ExReleaseResourceLite(&Fcb->MainResource);
603 }
604
605 if (VcbResourceAcquired) {
606 ExReleaseResourceLite(&Vcb->MainResource);
607 }
608
609 if (!_SEH2_AbnormalTermination()) {
610 Ext2CompleteIrpContext(IrpContext, Status);
611 }
612 } _SEH2_END;
613
614 return Status;
615 }
616
617 NTSTATUS
618 Ext2IsVolumeDirty (
619 IN PEXT2_IRP_CONTEXT IrpContext
620 )
621 {
622 NTSTATUS status = STATUS_SUCCESS;
623 PIRP Irp;
624 PEXTENDED_IO_STACK_LOCATION IrpSp;
625 PULONG VolumeState;
626
627 _SEH2_TRY {
628
629 Irp = IrpContext->Irp;
630 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
631
632 //
633 // Get a pointer to the output buffer. Look at the system buffer field in th
634 // irp first. Then the Irp Mdl.
635 //
636
637 if (Irp->AssociatedIrp.SystemBuffer != NULL) {
638
639 VolumeState = Irp->AssociatedIrp.SystemBuffer;
640
641 } else if (Irp->MdlAddress != NULL) {
642
643 VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress );
644
645 } else {
646
647 status = STATUS_INVALID_USER_BUFFER;
648 _SEH2_LEAVE;
649 }
650
651 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
652 status = STATUS_INVALID_PARAMETER;
653 _SEH2_LEAVE;
654 }
655
656 *VolumeState = 0;
657
658 } _SEH2_FINALLY {
659
660 if (!IrpContext->ExceptionInProgress) {
661 Ext2CompleteIrpContext(IrpContext, status);
662 }
663 } _SEH2_END;
664
665 return status;
666 }
667
668
669 NTSTATUS
670 Ext2QueryExtentMappings(
671 IN PEXT2_IRP_CONTEXT IrpContext,
672 IN PEXT2_VCB Vcb,
673 IN PEXT2_FCB Fcb,
674 IN PLARGE_INTEGER RequestVbn,
675 OUT PLARGE_INTEGER * pMappedRuns
676 )
677 {
678 PLARGE_INTEGER MappedRuns = NULL;
679 PLARGE_INTEGER PartialRuns = NULL;
680
681 PEXT2_EXTENT Chain = NULL;
682 PEXT2_EXTENT Extent = NULL;
683
684 LONGLONG Vbn = 0;
685 ULONG Length = 0;
686 ULONG i = 0;
687
688 NTSTATUS Status = STATUS_SUCCESS;
689
690 _SEH2_TRY {
691
692 /* now building all the request extents */
693 while (Vbn < RequestVbn->QuadPart) {
694
695 Length = 0x80000000; /* 2g bytes */
696 if (RequestVbn->QuadPart < Vbn + Length) {
697 Length = (ULONG)(RequestVbn->QuadPart - Vbn);
698 }
699
700 /* build extents for sub-range */
701 Extent = NULL;
702 Status = Ext2BuildExtents(
703 IrpContext,
704 Vcb,
705 Fcb->Mcb,
706 Vbn,
707 Length,
708 FALSE,
709 &Extent);
710
711 if (!NT_SUCCESS(Status)) {
712 _SEH2_LEAVE;
713 }
714
715 if (Chain) {
716 Ext2JointExtents(Chain, Extent);
717 } else {
718 Chain = Extent;
719 }
720
721 /* allocate extent array */
722 PartialRuns = Ext2AllocatePool(
723 NonPagedPool,
724 (Ext2CountExtents(Chain) + 2) *
725 (2 * sizeof(LARGE_INTEGER)),
726 'RE2E');
727
728 if (PartialRuns == NULL) {
729 Status = STATUS_INSUFFICIENT_RESOURCES;
730 _SEH2_LEAVE;
731 }
732 RtlZeroMemory( PartialRuns,
733 (Ext2CountExtents(Chain) + 2) *
734 (2 * sizeof(LARGE_INTEGER)));
735
736 if (MappedRuns) {
737 RtlMoveMemory(PartialRuns,
738 MappedRuns,
739 i * 2 * sizeof(LARGE_INTEGER));
740 Ext2FreePool(MappedRuns, 'RE2E');
741 }
742 MappedRuns = PartialRuns;
743
744 /* walk all the Mcb runs in Extent */
745 for (; Extent != NULL; Extent = Extent->Next) {
746 MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset;
747 MappedRuns[i*2 + 1].QuadPart = Extent->Lba;
748 i = i+1;
749 }
750
751 Vbn = Vbn + Length;
752 }
753
754 *pMappedRuns = MappedRuns;
755
756 } _SEH2_FINALLY {
757
758 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) {
759 if (MappedRuns) {
760 Ext2FreePool(MappedRuns, 'RE2E');
761 }
762 *pMappedRuns = NULL;
763 }
764
765 if (Chain) {
766 Ext2DestroyExtentChain(Chain);
767 }
768 } _SEH2_END;
769
770 return Status;
771 }
772
773 NTSTATUS
774 Ext2QueryRetrievalPointers (
775 IN PEXT2_IRP_CONTEXT IrpContext
776 )
777 {
778 PIRP Irp = NULL;
779 PIO_STACK_LOCATION IrpSp;
780 PEXTENDED_IO_STACK_LOCATION EIrpSp;
781
782 PDEVICE_OBJECT DeviceObject;
783 PFILE_OBJECT FileObject;
784
785 PEXT2_VCB Vcb = NULL;
786 PEXT2_FCB Fcb = NULL;
787 PEXT2_CCB Ccb = NULL;
788
789 PLARGE_INTEGER RequestVbn;
790 PLARGE_INTEGER * pMappedRuns;
791
792 ULONG InputSize;
793 ULONG OutputSize;
794
795 NTSTATUS Status = STATUS_SUCCESS;
796
797 BOOLEAN FcbResourceAcquired = FALSE;
798
799 _SEH2_TRY {
800
801 ASSERT(IrpContext);
802 Irp = IrpContext->Irp;
803 ASSERT(Irp);
804
805 IrpSp = IoGetCurrentIrpStackLocation(Irp);
806 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
807 ASSERT(IrpSp);
808
809 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
810 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
811
812 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
813 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
814
815 DeviceObject = IrpContext->DeviceObject;
816
817 DbgBreak();
818
819 /* This request is not allowed on the main device object */
820 if (IsExt2FsDevice(DeviceObject)) {
821 Status = STATUS_INVALID_DEVICE_REQUEST;
822 _SEH2_LEAVE;
823 }
824
825 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
826 ASSERT(Vcb != NULL);
827 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
828 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
829 ASSERT(IsMounted(Vcb));
830
831 FileObject = IrpContext->FileObject;
832 Fcb = (PEXT2_FCB) FileObject->FsContext;
833
834 /* check Fcb is valid or not */
835 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
836 Status = STATUS_INVALID_PARAMETER;
837 _SEH2_LEAVE;
838 }
839
840 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
841 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
842 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
843 Status = STATUS_FILE_DELETED;
844 _SEH2_LEAVE;
845 }
846
847 Ccb = (PEXT2_CCB) FileObject->FsContext2;
848 if (Ccb == NULL) {
849 Status = STATUS_INVALID_PARAMETER;
850 _SEH2_LEAVE;
851 }
852
853 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
854 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
855
856 /* Is requstor in kernel and Fcb a paging file ? */
857 if (Irp->RequestorMode != KernelMode ||
858 !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) ||
859 InputSize != sizeof(LARGE_INTEGER) ||
860 OutputSize != sizeof(PVOID)) {
861 Status = STATUS_INVALID_PARAMETER;
862 _SEH2_LEAVE;
863 }
864
865 if (!ExAcquireResourceExclusiveLite (
866 &Fcb->MainResource, Ext2CanIWait())) {
867 Status = STATUS_PENDING;
868 _SEH2_LEAVE;
869 }
870 FcbResourceAcquired = TRUE;
871
872 RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
873 pMappedRuns = Irp->UserBuffer;
874
875 DbgBreak();
876
877 /* request size beyonds whole file size */
878 if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
879 Status = STATUS_END_OF_FILE;
880 _SEH2_LEAVE;
881 }
882
883 Status = Ext2QueryExtentMappings(
884 IrpContext,
885 Vcb,
886 Fcb,
887 RequestVbn,
888 pMappedRuns
889 );
890
891 } _SEH2_FINALLY {
892
893 if (FcbResourceAcquired) {
894 ExReleaseResourceLite(&Fcb->MainResource);
895 }
896
897 if (!_SEH2_AbnormalTermination()) {
898 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
899 Status = Ext2QueueRequest(IrpContext);
900 } else {
901 Ext2CompleteIrpContext(IrpContext, Status);
902 }
903 }
904 } _SEH2_END;
905
906 return Status;
907 }
908
909
910 NTSTATUS
911 Ext2GetRetrievalPointers (
912 IN PEXT2_IRP_CONTEXT IrpContext
913 )
914 {
915 PIRP Irp = NULL;
916 PIO_STACK_LOCATION IrpSp;
917 PEXTENDED_IO_STACK_LOCATION EIrpSp;
918
919 PDEVICE_OBJECT DeviceObject;
920 PFILE_OBJECT FileObject;
921
922 PEXT2_VCB Vcb = NULL;
923 PEXT2_FCB Fcb = NULL;
924 PEXT2_CCB Ccb = NULL;
925
926 PSTARTING_VCN_INPUT_BUFFER SVIB;
927 PRETRIEVAL_POINTERS_BUFFER RPSB;
928
929 PEXT2_EXTENT Chain = NULL;
930 PEXT2_EXTENT Extent = NULL;
931
932 LONGLONG Vbn = 0;
933 ULONG Length = 0;
934 ULONG i = 0;
935
936 ULONG UsedSize = 0;
937 ULONG InputSize;
938 ULONG OutputSize;
939
940 NTSTATUS Status = STATUS_SUCCESS;
941
942 BOOLEAN FcbResourceAcquired = FALSE;
943
944 _SEH2_TRY {
945
946 ASSERT(IrpContext);
947 Irp = IrpContext->Irp;
948 ASSERT(Irp);
949
950 IrpSp = IoGetCurrentIrpStackLocation(Irp);
951 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
952 ASSERT(IrpSp);
953
954 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
955 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
956
957 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
958 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
959
960 DeviceObject = IrpContext->DeviceObject;
961
962 /* This request is not allowed on the main device object */
963 if (IsExt2FsDevice(DeviceObject)) {
964 Status = STATUS_INVALID_DEVICE_REQUEST;
965 _SEH2_LEAVE;
966 }
967
968 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
969 ASSERT(Vcb != NULL);
970 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
971 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
972 ASSERT(IsMounted(Vcb));
973
974 FileObject = IrpContext->FileObject;
975 Fcb = (PEXT2_FCB) FileObject->FsContext;
976
977 /* check Fcb is valid or not */
978 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
979 Status = STATUS_INVALID_PARAMETER;
980 _SEH2_LEAVE;
981 }
982
983 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
984 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
985
986 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
987 Status = STATUS_FILE_DELETED;
988 _SEH2_LEAVE;
989 }
990
991 Ccb = (PEXT2_CCB) FileObject->FsContext2;
992 if (Ccb == NULL) {
993 Status = STATUS_INVALID_PARAMETER;
994 _SEH2_LEAVE;
995 }
996
997 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
998 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
999
1000 if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) ||
1001 OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) {
1002 Status = STATUS_BUFFER_TOO_SMALL;
1003 _SEH2_LEAVE;
1004 }
1005
1006 if (!ExAcquireResourceExclusiveLite (
1007 &Fcb->MainResource, Ext2CanIWait())) {
1008 Status = STATUS_PENDING;
1009 _SEH2_LEAVE;
1010 }
1011 FcbResourceAcquired = TRUE;
1012
1013 SVIB = (PSTARTING_VCN_INPUT_BUFFER)
1014 EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
1015 RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp);
1016
1017 /* probe user buffer */
1018
1019 _SEH2_TRY {
1020 if (Irp->RequestorMode != KernelMode) {
1021 ProbeForRead (SVIB, InputSize, sizeof(UCHAR));
1022 ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR));
1023 }
1024 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1025 Status = STATUS_INVALID_USER_BUFFER;
1026 } _SEH2_END;
1027
1028 if (!NT_SUCCESS(Status)) {
1029 _SEH2_LEAVE;
1030 }
1031
1032 UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]);
1033
1034 /* request size beyonds whole file size ? */
1035 DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n",
1036 SVIB->StartingVcn.QuadPart));
1037 Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS);
1038 if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) {
1039 Status = STATUS_END_OF_FILE;
1040 _SEH2_LEAVE;
1041 }
1042
1043 /* now building all the request extents */
1044 while (Vbn < Fcb->Header.AllocationSize.QuadPart) {
1045
1046 ASSERT(Chain == NULL);
1047 Length = 0x80000000; /* 2g bytes */
1048 if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) {
1049 Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn);
1050 }
1051
1052 /* build extents for sub-range */
1053 Status = Ext2BuildExtents(
1054 IrpContext,
1055 Vcb,
1056 Fcb->Mcb,
1057 Vbn,
1058 Length,
1059 FALSE,
1060 &Chain);
1061
1062 if (!NT_SUCCESS(Status)) {
1063 DbgBreak();
1064 _SEH2_LEAVE;
1065 }
1066
1067 /* fill user buffer of RETRIEVAL_POINTERS_BUFFER */
1068 Extent = Chain;
1069 while (Extent) {
1070
1071 DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
1072 &Fcb->Mcb->FullName, i,
1073 ((Vbn + Extent->Offset) >> BLOCK_BITS),
1074 Extent->Lba));
1075
1076 RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS);
1077 RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS);
1078 if (i == 0) {
1079 RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS);
1080 } else {
1081 ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS));
1082 }
1083 if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) {
1084 Status = STATUS_BUFFER_OVERFLOW;
1085 _SEH2_LEAVE;
1086 }
1087 UsedSize += sizeof(LARGE_INTEGER) * 2;
1088 Irp->IoStatus.Information = (ULONG_PTR)UsedSize;
1089 RPSB->ExtentCount = ++i;
1090 Extent = Extent->Next;
1091 }
1092
1093 if (Chain) {
1094 Ext2DestroyExtentChain(Chain);
1095 Chain = NULL;
1096 }
1097
1098 Vbn = Vbn + Length;
1099 }
1100
1101 #if 0
1102 {
1103 NTSTATUS _s;
1104 ULONG _i = 0;
1105 LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize;
1106 PLARGE_INTEGER MappedRuns = NULL;
1107
1108 _s = Ext2QueryExtentMappings(
1109 IrpContext,
1110 Vcb,
1111 Fcb,
1112 &RequestVbn,
1113 &MappedRuns
1114 );
1115 if (!NT_SUCCESS(_s) || NULL == MappedRuns) {
1116 DbgBreak();
1117 goto exit_to_get_rps;
1118 }
1119
1120 while (MappedRuns[_i*2 + 0].QuadPart != 0 ||
1121 MappedRuns[_i*2 + 1].QuadPart != 0 ) {
1122 DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
1123 &Fcb->Mcb->FullName, _i,
1124 MappedRuns[_i*2 + 0].QuadPart,
1125 MappedRuns[_i*2 + 1].QuadPart));
1126 _i++;
1127 }
1128
1129 exit_to_get_rps:
1130
1131 if (MappedRuns) {
1132 Ext2FreePool(MappedRuns, 'RE2E');
1133 }
1134 }
1135 #endif
1136
1137 } _SEH2_FINALLY {
1138
1139 if (FcbResourceAcquired) {
1140 ExReleaseResourceLite(&Fcb->MainResource);
1141 }
1142
1143 if (Chain) {
1144 Ext2DestroyExtentChain(Chain);
1145 }
1146
1147 if (!_SEH2_AbnormalTermination()) {
1148 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1149 Status = Ext2QueueRequest(IrpContext);
1150 } else {
1151 Ext2CompleteIrpContext(IrpContext, Status);
1152 }
1153 }
1154 } _SEH2_END;
1155
1156 return Status;
1157 }
1158
1159 NTSTATUS
1160 Ext2GetRetrievalPointerBase (
1161 IN PEXT2_IRP_CONTEXT IrpContext
1162 )
1163 {
1164 PIRP Irp = NULL;
1165 PIO_STACK_LOCATION IrpSp;
1166 PEXTENDED_IO_STACK_LOCATION EIrpSp;
1167
1168 PDEVICE_OBJECT DeviceObject;
1169 PFILE_OBJECT FileObject;
1170
1171 PEXT2_VCB Vcb = NULL;
1172 PEXT2_FCB Fcb = NULL;
1173 PEXT2_CCB Ccb = NULL;
1174
1175 PLARGE_INTEGER FileAreaOffset;
1176
1177 ULONG OutputSize;
1178
1179 NTSTATUS Status = STATUS_SUCCESS;
1180
1181 BOOLEAN FcbResourceAcquired = FALSE;
1182
1183 _SEH2_TRY {
1184
1185 ASSERT(IrpContext);
1186 Irp = IrpContext->Irp;
1187 ASSERT(Irp);
1188
1189 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1190 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
1191 ASSERT(IrpSp);
1192
1193 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
1194
1195 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1196 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1197
1198 DeviceObject = IrpContext->DeviceObject;
1199
1200 /* This request is not allowed on the main device object */
1201 if (IsExt2FsDevice(DeviceObject)) {
1202 Status = STATUS_INVALID_DEVICE_REQUEST;
1203 _SEH2_LEAVE;
1204 }
1205
1206 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1207 ASSERT(Vcb != NULL);
1208 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1209 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1210 ASSERT(IsMounted(Vcb));
1211
1212 FileObject = IrpContext->FileObject;
1213 Fcb = (PEXT2_FCB) FileObject->FsContext;
1214
1215 /* check Fcb is valid or not */
1216 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
1217 Status = STATUS_INVALID_PARAMETER;
1218 _SEH2_LEAVE;
1219 }
1220
1221 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
1222 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
1223
1224 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
1225 Status = STATUS_FILE_DELETED;
1226 _SEH2_LEAVE;
1227 }
1228
1229 Ccb = (PEXT2_CCB) FileObject->FsContext2;
1230 if (Ccb == NULL) {
1231 Status = STATUS_INVALID_PARAMETER;
1232 _SEH2_LEAVE;
1233 }
1234
1235 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1236 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1237
1238 if (OutputSize < sizeof(LARGE_INTEGER)) {
1239 Status = STATUS_BUFFER_TOO_SMALL;
1240 _SEH2_LEAVE;
1241 }
1242
1243 if (!ExAcquireResourceExclusiveLite (
1244 &Fcb->MainResource, Ext2CanIWait())) {
1245 Status = STATUS_PENDING;
1246 _SEH2_LEAVE;
1247 }
1248 FcbResourceAcquired = TRUE;
1249
1250 FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp);
1251
1252 /* probe user buffer */
1253
1254 _SEH2_TRY {
1255 if (Irp->RequestorMode != KernelMode) {
1256 ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR));
1257 }
1258
1259 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1260
1261 Status = STATUS_INVALID_USER_BUFFER;
1262 } _SEH2_END;
1263
1264 if (!NT_SUCCESS(Status)) {
1265 _SEH2_LEAVE;
1266 }
1267
1268 DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n"));
1269
1270 FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem
1271
1272 Irp->IoStatus.Information = sizeof(LARGE_INTEGER);
1273
1274 } _SEH2_FINALLY {
1275
1276 if (FcbResourceAcquired) {
1277 ExReleaseResourceLite(&Fcb->MainResource);
1278 }
1279
1280 if (!_SEH2_AbnormalTermination()) {
1281 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1282 Status = Ext2QueueRequest(IrpContext);
1283 } else {
1284 Ext2CompleteIrpContext(IrpContext, Status);
1285 }
1286 }
1287 } _SEH2_END;
1288
1289 return Status;
1290 }
1291
1292
1293 NTSTATUS
1294 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
1295 {
1296 PIRP Irp;
1297 PIO_STACK_LOCATION IoStackLocation;
1298 ULONG FsControlCode;
1299 NTSTATUS Status;
1300
1301 ASSERT(IrpContext);
1302
1303 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1304 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1305
1306 Irp = IrpContext->Irp;
1307
1308 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1309
1310 #ifndef _GNU_NTIFS_
1311 FsControlCode =
1312 IoStackLocation->Parameters.FileSystemControl.FsControlCode;
1313 #else
1314 FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
1315 IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
1316 #endif
1317
1318 switch (FsControlCode) {
1319
1320 case FSCTL_LOCK_VOLUME:
1321 Status = Ext2LockVolume(IrpContext);
1322 break;
1323
1324 case FSCTL_UNLOCK_VOLUME:
1325 Status = Ext2UnlockVolume(IrpContext);
1326 break;
1327
1328 case FSCTL_DISMOUNT_VOLUME:
1329 Status = Ext2DismountVolume(IrpContext);
1330 break;
1331
1332 case FSCTL_IS_VOLUME_MOUNTED:
1333 Status = Ext2IsVolumeMounted(IrpContext);
1334 break;
1335
1336 case FSCTL_INVALIDATE_VOLUMES:
1337 Status = Ext2InvalidateVolumes(IrpContext);
1338 break;
1339
1340 #if (_WIN32_WINNT >= 0x0500)
1341 case FSCTL_ALLOW_EXTENDED_DASD_IO:
1342 Status = Ext2AllowExtendedDasdIo(IrpContext);
1343 break;
1344 #endif //(_WIN32_WINNT >= 0x0500)
1345
1346 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
1347 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
1348 case FSCTL_REQUEST_BATCH_OPLOCK:
1349 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
1350 case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
1351 case FSCTL_OPLOCK_BREAK_NOTIFY:
1352 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
1353
1354 Status = Ext2OplockRequest(IrpContext);
1355 break;
1356
1357 case FSCTL_IS_VOLUME_DIRTY:
1358 Status = Ext2IsVolumeDirty(IrpContext);
1359 break;
1360
1361 case FSCTL_QUERY_RETRIEVAL_POINTERS:
1362 Status = Ext2QueryRetrievalPointers(IrpContext);
1363 break;
1364
1365 case FSCTL_GET_RETRIEVAL_POINTERS:
1366 Status = Ext2GetRetrievalPointers(IrpContext);
1367 break;
1368
1369 case FSCTL_GET_RETRIEVAL_POINTER_BASE:
1370 Status = Ext2GetRetrievalPointerBase(IrpContext);
1371 break;
1372
1373 default:
1374
1375 DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
1376 Status = STATUS_INVALID_DEVICE_REQUEST;
1377
1378 Ext2CompleteIrpContext(IrpContext, Status);
1379 }
1380
1381 return Status;
1382 }
1383
1384 BOOLEAN
1385 Ext2IsMediaWriteProtected (
1386 IN PEXT2_IRP_CONTEXT IrpContext,
1387 IN PDEVICE_OBJECT TargetDevice
1388 )
1389 {
1390 PIRP Irp;
1391 KEVENT Event;
1392 NTSTATUS Status;
1393 IO_STATUS_BLOCK IoStatus;
1394
1395 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1396
1397 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
1398 TargetDevice,
1399 NULL,
1400 0,
1401 NULL,
1402 0,
1403 FALSE,
1404 &Event,
1405 &IoStatus );
1406
1407 if (Irp == NULL) {
1408 return FALSE;
1409 }
1410
1411 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
1412
1413 Status = IoCallDriver(TargetDevice, Irp);
1414
1415 if (Status == STATUS_PENDING) {
1416
1417 (VOID) KeWaitForSingleObject( &Event,
1418 Executive,
1419 KernelMode,
1420 FALSE,
1421 (PLARGE_INTEGER)NULL );
1422
1423 Status = IoStatus.Status;
1424 }
1425
1426 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
1427 }
1428
1429 NTSTATUS
1430 Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
1431 {
1432 PDEVICE_OBJECT MainDeviceObject;
1433 BOOLEAN GlobalDataResourceAcquired = FALSE;
1434 PIRP Irp;
1435 PIO_STACK_LOCATION IoStackLocation;
1436 PDEVICE_OBJECT TargetDeviceObject;
1437 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
1438 PDEVICE_OBJECT VolumeDeviceObject = NULL;
1439 PEXT2_VCB Vcb = NULL, OldVcb = NULL;
1440 PVPB OldVpb = NULL, Vpb = NULL;
1441 PEXT2_SUPER_BLOCK Ext2Sb = NULL;
1442 ULONG dwBytes;
1443 DISK_GEOMETRY DiskGeometry;
1444
1445 _SEH2_TRY {
1446
1447 ASSERT(IrpContext != NULL);
1448 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1449 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1450
1451 MainDeviceObject = IrpContext->DeviceObject;
1452
1453 //
1454 // Make sure we can wait.
1455 //
1456
1457 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1458
1459 //
1460 // This request is only allowed on the main device object
1461 //
1462 if (!IsExt2FsDevice(MainDeviceObject)) {
1463 Status = STATUS_INVALID_DEVICE_REQUEST;
1464 _SEH2_LEAVE;
1465 }
1466
1467 if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
1468 Status = STATUS_UNRECOGNIZED_VOLUME;
1469 _SEH2_LEAVE;
1470 }
1471
1472 #if 0
1473 if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
1474 *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
1475 } else {
1476 Status = STATUS_UNRECOGNIZED_VOLUME;
1477 _SEH2_LEAVE;
1478 }
1479 #endif
1480
1481 Irp = IrpContext->Irp;
1482 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1483 TargetDeviceObject =
1484 IoStackLocation->Parameters.MountVolume.DeviceObject;
1485
1486 dwBytes = sizeof(DISK_GEOMETRY);
1487 Status = Ext2DiskIoControl(
1488 TargetDeviceObject,
1489 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1490 NULL,
1491 0,
1492 &DiskGeometry,
1493 &dwBytes );
1494
1495 if (!NT_SUCCESS(Status)) {
1496 _SEH2_LEAVE;
1497 }
1498
1499 #ifdef __REACTOS__
1500 if (DiskGeometry.MediaType == Unknown)
1501 {
1502 DiskGeometry.BytesPerSector = 512;
1503 }
1504 #endif
1505
1506 Status = IoCreateDevice(
1507 MainDeviceObject->DriverObject,
1508 sizeof(EXT2_VCB),
1509 NULL,
1510 FILE_DEVICE_DISK_FILE_SYSTEM,
1511 0,
1512 FALSE,
1513 &VolumeDeviceObject );
1514
1515 if (!NT_SUCCESS(Status)) {
1516 _SEH2_LEAVE;
1517 }
1518 INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
1519
1520 VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
1521 ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
1522
1523 if (TargetDeviceObject->AlignmentRequirement >
1524 VolumeDeviceObject->AlignmentRequirement) {
1525
1526 VolumeDeviceObject->AlignmentRequirement =
1527 TargetDeviceObject->AlignmentRequirement;
1528 }
1529
1530 (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
1531 VolumeDeviceObject;
1532 Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
1533
1534 Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
1535
1536 RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
1537 Vcb->Identifier.Type = EXT2VCB;
1538 Vcb->Identifier.Size = sizeof(EXT2_VCB);
1539 Vcb->TargetDeviceObject = TargetDeviceObject;
1540 Vcb->DiskGeometry = DiskGeometry;
1541 InitializeListHead(&Vcb->Next);
1542
1543 Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
1544 if (!NT_SUCCESS(Status)) {
1545 Vcb = NULL;
1546 Status = STATUS_UNRECOGNIZED_VOLUME;
1547 _SEH2_LEAVE;
1548 }
1549 ASSERT (NULL != Ext2Sb);
1550
1551 /* check Linux Ext2/Ext3 volume magic */
1552 if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
1553 DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
1554 } else {
1555 Status = STATUS_UNRECOGNIZED_VOLUME;
1556 Vcb = NULL;
1557 _SEH2_LEAVE;
1558 }
1559
1560 DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
1561
1562 /* initialize Vcb structure */
1563 Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
1564 TargetDeviceObject,
1565 VolumeDeviceObject, Vpb);
1566
1567 if (NT_SUCCESS(Status)) {
1568
1569 PLIST_ENTRY List;
1570
1571 ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
1572 GlobalDataResourceAcquired = TRUE;
1573
1574 for (List = Ext2Global->VcbList.Flink;
1575 List != &Ext2Global->VcbList;
1576 List = List->Flink) {
1577
1578 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
1579 OldVpb = OldVcb->Vpb;
1580
1581 /* in case we are already in the queue, should not happen */
1582 if (OldVpb == Vpb) {
1583 continue;
1584 }
1585
1586 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
1587 (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
1588 (OldVpb->RealDevice == TargetDeviceObject) &&
1589 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
1590 (RtlEqualMemory(&OldVpb->VolumeLabel[0],
1591 &Vpb->VolumeLabel[0],
1592 Vpb->VolumeLabelLength)) &&
1593 (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
1594 &Vcb->SuperBlock->s_uuid[0], 16)) ) {
1595 ClearFlag(OldVcb->Flags, VCB_MOUNTED);
1596 }
1597 }
1598
1599 SetLongFlag(Vcb->Flags, VCB_MOUNTED);
1600 SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
1601 Ext2InsertVcb(Vcb);
1602 Vcb = NULL;
1603 Vpb = NULL;
1604 ObDereferenceObject(TargetDeviceObject);
1605
1606 } else {
1607
1608 Vcb = NULL;
1609 }
1610
1611 } _SEH2_FINALLY {
1612
1613 if (GlobalDataResourceAcquired) {
1614 ExReleaseResourceLite(&Ext2Global->Resource);
1615 }
1616
1617 if (!NT_SUCCESS(Status)) {
1618
1619 if (!NT_SUCCESS(Status)) {
1620 if ( Vpb != NULL ) {
1621 Vpb->DeviceObject = NULL;
1622 }
1623 }
1624
1625 if (Vcb) {
1626 Ext2DestroyVcb(Vcb);
1627 } else {
1628 if (Ext2Sb) {
1629 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
1630 }
1631 if (VolumeDeviceObject) {
1632 IoDeleteDevice(VolumeDeviceObject);
1633 DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
1634 }
1635 }
1636 }
1637
1638 if (!IrpContext->ExceptionInProgress) {
1639 Ext2CompleteIrpContext(IrpContext, Status);
1640 }
1641 } _SEH2_END;
1642
1643 return Status;
1644 }
1645
1646 VOID
1647 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
1648 IN PEXT2_VCB Vcb )
1649 {
1650 NTSTATUS Status = STATUS_SUCCESS;
1651
1652 BOOLEAN bVerify = FALSE;
1653 ULONG ChangeCount = 0;
1654 ULONG dwBytes;
1655
1656 PIRP Irp;
1657 PEXTENDED_IO_STACK_LOCATION IrpSp;
1658
1659 _SEH2_TRY {
1660
1661 ASSERT(IrpContext != NULL);
1662
1663 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1664 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1665
1666 Irp = IrpContext->Irp;
1667 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
1668
1669 bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1670
1671 if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
1672 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
1673
1674 dwBytes = sizeof(ULONG);
1675 Status = Ext2DiskIoControl(
1676 Vcb->TargetDeviceObject,
1677 IOCTL_DISK_CHECK_VERIFY,
1678 NULL,
1679 0,
1680 &ChangeCount,
1681 &dwBytes );
1682
1683 if ( STATUS_VERIFY_REQUIRED == Status ||
1684 STATUS_DEVICE_NOT_READY == Status ||
1685 STATUS_NO_MEDIA_IN_DEVICE == Status ||
1686 (NT_SUCCESS(Status) &&
1687 (ChangeCount != Vcb->ChangeCount))) {
1688
1689 KIRQL Irql;
1690
1691 IoAcquireVpbSpinLock(&Irql);
1692 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
1693 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1694 }
1695 IoReleaseVpbSpinLock(Irql);
1696
1697 } else {
1698
1699 if (!NT_SUCCESS(Status)) {
1700 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
1701 }
1702 }
1703 }
1704
1705 if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
1706 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
1707 Ext2NormalizeAndRaiseStatus ( IrpContext,
1708 STATUS_VERIFY_REQUIRED );
1709 }
1710
1711 if (IsMounted(Vcb)) {
1712
1713 if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
1714 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
1715 (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
1716 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
1717 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
1718 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1719 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
1720 IrpSp->Parameters.FileSystemControl.FsControlCode ==
1721 FSCTL_MARK_VOLUME_DIRTY)) {
1722
1723 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
1724
1725 KIRQL Irql;
1726
1727 IoAcquireVpbSpinLock(&Irql);
1728 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
1729 SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1730 }
1731 IoReleaseVpbSpinLock(Irql);
1732
1733 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
1734
1735 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
1736 }
1737 }
1738 }
1739
1740 } _SEH2_FINALLY {
1741
1742 } _SEH2_END;
1743
1744 }
1745
1746
1747 NTSTATUS
1748 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
1749 {
1750 PDEVICE_OBJECT DeviceObject;
1751 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1752 PEXT2_SUPER_BLOCK ext2_sb = NULL;
1753 PEXT2_VCB Vcb = NULL;
1754 BOOLEAN VcbResourceAcquired = FALSE;
1755 PIRP Irp;
1756 ULONG ChangeCount = 0;
1757 ULONG dwBytes;
1758
1759 _SEH2_TRY {
1760
1761 ASSERT(IrpContext != NULL);
1762 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1763 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1764
1765 DeviceObject = IrpContext->DeviceObject;
1766 //
1767 // This request is not allowed on the main device object
1768 //
1769 if (IsExt2FsDevice(DeviceObject)) {
1770 Status = STATUS_INVALID_DEVICE_REQUEST;
1771 _SEH2_LEAVE;
1772 }
1773
1774 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1775 ASSERT(Vcb != NULL);
1776 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1777 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1778
1779 VcbResourceAcquired =
1780 ExAcquireResourceExclusiveLite(
1781 &Vcb->MainResource,
1782 TRUE );
1783
1784 if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
1785 Status = STATUS_SUCCESS;
1786 _SEH2_LEAVE;
1787 }
1788
1789 if (!IsMounted(Vcb)) {
1790 Status = STATUS_WRONG_VOLUME;
1791 _SEH2_LEAVE;
1792 }
1793
1794 dwBytes = sizeof(ULONG);
1795 Status = Ext2DiskIoControl(
1796 Vcb->TargetDeviceObject,
1797 IOCTL_DISK_CHECK_VERIFY,
1798 NULL,
1799 0,
1800 &ChangeCount,
1801 &dwBytes );
1802
1803
1804 if (!NT_SUCCESS(Status)) {
1805 Status = STATUS_WRONG_VOLUME;
1806 _SEH2_LEAVE;
1807 } else {
1808 Vcb->ChangeCount = ChangeCount;
1809 }
1810
1811 Irp = IrpContext->Irp;
1812
1813 Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
1814
1815 if (!NT_SUCCESS(Status)) {
1816 _SEH2_LEAVE;
1817 }
1818
1819 ASSERT(NULL != ext2_sb);
1820 if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
1821 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
1822 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
1823
1824 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
1825
1826 if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
1827 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
1828 } else {
1829 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
1830 }
1831
1832 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
1833
1834 } else {
1835
1836 Status = STATUS_WRONG_VOLUME;
1837 if (VcbResourceAcquired) {
1838 ExReleaseResourceLite(&Vcb->MainResource);
1839 VcbResourceAcquired = FALSE;
1840 }
1841 Ext2PurgeVolume(Vcb, FALSE);
1842 VcbResourceAcquired =
1843 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
1844
1845 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
1846 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
1847
1848 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
1849 }
1850
1851 } _SEH2_FINALLY {
1852
1853 if (ext2_sb)
1854 Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
1855
1856 if (VcbResourceAcquired) {
1857 ExReleaseResourceLite(&Vcb->MainResource);
1858 }
1859
1860 if (!IrpContext->ExceptionInProgress) {
1861 Ext2CompleteIrpContext(IrpContext, Status);
1862 }
1863 } _SEH2_END;
1864
1865 return Status;
1866 }
1867
1868
1869 NTSTATUS
1870 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
1871 {
1872 PDEVICE_OBJECT DeviceObject;
1873 PEXT2_VCB Vcb = 0;
1874 NTSTATUS Status = STATUS_SUCCESS;
1875
1876 ASSERT(IrpContext);
1877
1878 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1879 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1880
1881
1882 DeviceObject = IrpContext->DeviceObject;
1883
1884 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1885
1886 ASSERT(IsMounted(Vcb));
1887
1888 Ext2VerifyVcb (IrpContext, Vcb);
1889
1890 Ext2CompleteIrpContext(IrpContext, Status);
1891
1892 return Status;
1893 }
1894
1895
1896 NTSTATUS
1897 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
1898 {
1899 PDEVICE_OBJECT DeviceObject;
1900 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1901 PEXT2_VCB Vcb;
1902 BOOLEAN VcbResourceAcquired = FALSE;
1903
1904 _SEH2_TRY {
1905
1906 ASSERT(IrpContext != NULL);
1907
1908 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1909 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1910
1911 DeviceObject = IrpContext->DeviceObject;
1912
1913 //
1914 // This request is not allowed on the main device object
1915 //
1916 if (IsExt2FsDevice(DeviceObject)) {
1917 Status = STATUS_INVALID_DEVICE_REQUEST;
1918 _SEH2_LEAVE;
1919 }
1920
1921 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1922
1923 ASSERT(Vcb != NULL);
1924
1925 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1926 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1927
1928 ASSERT(IsMounted(Vcb));
1929
1930 ExAcquireResourceExclusiveLite(
1931 &Vcb->MainResource,
1932 TRUE );
1933
1934 VcbResourceAcquired = TRUE;
1935
1936 if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
1937 Status = STATUS_VOLUME_DISMOUNTED;
1938 _SEH2_LEAVE;
1939 }
1940
1941 Ext2FlushFiles(IrpContext, Vcb, FALSE);
1942 Ext2FlushVolume(IrpContext, Vcb, FALSE);
1943
1944 ExReleaseResourceLite(&Vcb->MainResource);
1945 VcbResourceAcquired = FALSE;
1946
1947 Ext2PurgeVolume(Vcb, TRUE);
1948 Ext2CheckDismount(IrpContext, Vcb, TRUE);
1949
1950 DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
1951 Status = STATUS_SUCCESS;
1952
1953 } _SEH2_FINALLY {
1954
1955 if (VcbResourceAcquired) {
1956 ExReleaseResourceLite(&Vcb->MainResource);
1957 }
1958
1959 if (!IrpContext->ExceptionInProgress) {
1960 Ext2CompleteIrpContext(IrpContext, Status);
1961 }
1962 } _SEH2_END;
1963
1964 return Status;
1965 }
1966
1967 BOOLEAN
1968 Ext2CheckDismount (
1969 IN PEXT2_IRP_CONTEXT IrpContext,
1970 IN PEXT2_VCB Vcb,
1971 IN BOOLEAN bForce )
1972 {
1973 KIRQL Irql;
1974 PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
1975 BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
1976 ULONG UnCleanCount = 0;
1977
1978 NewVpb = Ext2AllocatePool(NonPagedPool, VPB_SIZE, TAG_VPB);
1979 if (NewVpb == NULL) {
1980 DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
1981 return FALSE;
1982 }
1983 INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
1984 memset(NewVpb, '_', VPB_SIZE);
1985 RtlZeroMemory(NewVpb, sizeof(VPB));
1986
1987 ExAcquireResourceExclusiveLite(
1988 &Ext2Global->Resource, TRUE );
1989
1990 ExAcquireResourceExclusiveLite(
1991 &Vcb->MainResource, TRUE );
1992
1993 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
1994 (IrpContext->RealDevice == Vcb->RealDevice)) {
1995 UnCleanCount = 3;
1996 } else {
1997 UnCleanCount = 2;
1998 }
1999
2000 IoAcquireVpbSpinLock (&Irql);
2001
2002 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
2003 Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
2004 if (Vpb->ReferenceCount <= UnCleanCount) {
2005
2006 if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2007
2008 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2009 ClearFlag(Vpb->Flags, VPB_LOCKED);
2010
2011 if ((Vcb->RealDevice != Vpb->RealDevice) &&
2012 (Vcb->RealDevice->Vpb == Vpb)) {
2013 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
2014 SetFlag(Vpb->Flags, VPB_PERSISTENT );
2015 }
2016
2017 Ext2RemoveVcb(Vcb);
2018 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2019 }
2020
2021 if (Vpb->ReferenceCount) {
2022 bTearDown = TRUE;
2023 } else {
2024 bDeleted = TRUE;
2025 Vpb->DeviceObject = NULL;
2026 }
2027
2028 } else if (bForce) {
2029
2030 DEBUG(DL_DBG, ( "Ext2CheckDismount: NewVpb %p Realdevice = %p\n",
2031 NewVpb, Vpb->RealDevice));
2032
2033 Vcb->Vpb2 = Vcb->Vpb;
2034 NewVpb->Type = IO_TYPE_VPB;
2035 NewVpb->Size = sizeof(VPB);
2036 NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
2037 NewVpb->RealDevice = Vpb->RealDevice;
2038 NewVpb->RealDevice->Vpb = NewVpb;
2039 NewVpb = NULL;
2040 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2041 SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
2042 ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
2043 }
2044
2045 IoReleaseVpbSpinLock(Irql);
2046
2047 ExReleaseResourceLite(&Vcb->MainResource);
2048 ExReleaseResourceLite(&Ext2Global->Resource);
2049
2050 if (bTearDown) {
2051 DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
2052 Ext2TearDownStream(Vcb);
2053 }
2054
2055 if (bDeleted) {
2056 DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
2057 Ext2DestroyVcb(Vcb);
2058 }
2059
2060 if (NewVpb != NULL) {
2061 DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing Vpb %p\n", NewVpb));
2062 Ext2FreePool(NewVpb, TAG_VPB);
2063 DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2064 }
2065
2066 return bDeleted;
2067 }
2068
2069 NTSTATUS
2070 Ext2PurgeVolume (IN PEXT2_VCB Vcb,
2071 IN BOOLEAN FlushBeforePurge )
2072 {
2073 PEXT2_FCB Fcb;
2074 LIST_ENTRY FcbList;
2075 PLIST_ENTRY ListEntry;
2076 PFCB_LIST_ENTRY FcbListEntry;
2077 BOOLEAN VcbResourceAcquired = FALSE;
2078 _SEH2_TRY {
2079
2080 ASSERT(Vcb != NULL);
2081 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2082 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2083
2084 VcbResourceAcquired =
2085 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2086
2087 if (IsVcbReadOnly(Vcb)) {
2088 FlushBeforePurge = FALSE;
2089 }
2090
2091 Ext2PutGroup(Vcb);
2092
2093 FcbListEntry= NULL;
2094 InitializeListHead(&FcbList);
2095
2096 for (ListEntry = Vcb->FcbList.Flink;
2097 ListEntry != &Vcb->FcbList;
2098 ListEntry = ListEntry->Flink ) {
2099
2100 Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
2101
2102 DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", &Fcb->Mcb->FullName, Fcb->ReferenceCount));
2103
2104 FcbListEntry = Ext2AllocatePool(
2105 PagedPool,
2106 sizeof(FCB_LIST_ENTRY),
2107 EXT2_FLIST_MAGIC
2108 );
2109
2110 if (FcbListEntry) {
2111 FcbListEntry->Fcb = Fcb;
2112 Ext2ReferXcb(&Fcb->ReferenceCount);
2113 InsertTailList(&FcbList, &FcbListEntry->Next);
2114 } else {
2115 DEBUG(DL_ERR, ( "Ext2PurgeVolume: failed to allocate FcbListEntry ...\n"));
2116 }
2117 }
2118
2119 while (!IsListEmpty(&FcbList)) {
2120
2121 ListEntry = RemoveHeadList(&FcbList);
2122
2123 FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
2124
2125 Fcb = FcbListEntry->Fcb;
2126
2127 if (ExAcquireResourceExclusiveLite(
2128 &Fcb->MainResource,
2129 TRUE )) {
2130
2131 Ext2PurgeFile(Fcb, FlushBeforePurge);
2132
2133 if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
2134 Ext2FreeFcb(Fcb);
2135 } else {
2136 ExReleaseResourceLite(&Fcb->MainResource);
2137 }
2138 }
2139
2140 Ext2FreePool(FcbListEntry, EXT2_FLIST_MAGIC);
2141 }
2142
2143 if (FlushBeforePurge) {
2144 ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
2145 ExReleaseResourceLite(&Vcb->PagingIoResource);
2146
2147 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
2148 }
2149
2150 if (Vcb->SectionObject.ImageSectionObject) {
2151 MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
2152 }
2153
2154 if (VcbResourceAcquired) {
2155 ExReleaseResourceLite(&Vcb->MainResource);
2156 VcbResourceAcquired = FALSE;
2157 }
2158
2159 if (Vcb->SectionObject.DataSectionObject) {
2160 CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
2161 }
2162
2163 DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
2164
2165 } _SEH2_FINALLY {
2166
2167 if (VcbResourceAcquired) {
2168 ExReleaseResourceLite(&Vcb->MainResource);
2169 }
2170 } _SEH2_END;
2171
2172 return STATUS_SUCCESS;
2173 }
2174
2175 NTSTATUS
2176 Ext2PurgeFile ( IN PEXT2_FCB Fcb,
2177 IN BOOLEAN FlushBeforePurge )
2178 {
2179 IO_STATUS_BLOCK IoStatus;
2180
2181 ASSERT(Fcb != NULL);
2182
2183 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
2184 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
2185
2186
2187 if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
2188
2189 DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
2190 &Fcb->Mcb->FullName));
2191
2192 ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
2193 ExReleaseResourceLite(&Fcb->PagingIoResource);
2194
2195 CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
2196 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
2197 }
2198
2199 if (Fcb->SectionObject.ImageSectionObject) {
2200
2201 DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
2202 &Fcb->Mcb->FullName));
2203
2204 MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
2205 }
2206
2207 if (Fcb->SectionObject.DataSectionObject) {
2208
2209 DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
2210 &Fcb->Mcb->FullName));
2211
2212 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
2213 }
2214
2215 return STATUS_SUCCESS;
2216 }
2217
2218
2219 NTSTATUS
2220 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
2221 {
2222 NTSTATUS Status;
2223
2224 ASSERT(IrpContext);
2225
2226 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2227 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2228
2229 switch (IrpContext->MinorFunction) {
2230
2231 case IRP_MN_USER_FS_REQUEST:
2232 Status = Ext2UserFsRequest(IrpContext);
2233 break;
2234
2235 case IRP_MN_MOUNT_VOLUME:
2236 Status = Ext2MountVolume(IrpContext);
2237 break;
2238
2239 case IRP_MN_VERIFY_VOLUME:
2240 Status = Ext2VerifyVolume(IrpContext);
2241 break;
2242
2243 default:
2244
2245 DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
2246 Status = STATUS_INVALID_DEVICE_REQUEST;
2247 Ext2CompleteIrpContext(IrpContext, Status);
2248 }
2249
2250 return Status;
2251 }