[PSDK]
[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 Status = IoCreateDevice(
1500 MainDeviceObject->DriverObject,
1501 sizeof(EXT2_VCB),
1502 NULL,
1503 FILE_DEVICE_DISK_FILE_SYSTEM,
1504 0,
1505 FALSE,
1506 &VolumeDeviceObject );
1507
1508 if (!NT_SUCCESS(Status)) {
1509 _SEH2_LEAVE;
1510 }
1511 INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
1512
1513 VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
1514 ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
1515
1516 if (TargetDeviceObject->AlignmentRequirement >
1517 VolumeDeviceObject->AlignmentRequirement) {
1518
1519 VolumeDeviceObject->AlignmentRequirement =
1520 TargetDeviceObject->AlignmentRequirement;
1521 }
1522
1523 (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
1524 VolumeDeviceObject;
1525 Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
1526
1527 Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
1528
1529 RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
1530 Vcb->Identifier.Type = EXT2VCB;
1531 Vcb->Identifier.Size = sizeof(EXT2_VCB);
1532 Vcb->TargetDeviceObject = TargetDeviceObject;
1533 Vcb->DiskGeometry = DiskGeometry;
1534 InitializeListHead(&Vcb->Next);
1535
1536 Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
1537 if (!NT_SUCCESS(Status)) {
1538 Vcb = NULL;
1539 Status = STATUS_UNRECOGNIZED_VOLUME;
1540 _SEH2_LEAVE;
1541 }
1542 ASSERT (NULL != Ext2Sb);
1543
1544 /* check Linux Ext2/Ext3 volume magic */
1545 if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
1546 DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
1547 } else {
1548 Status = STATUS_UNRECOGNIZED_VOLUME;
1549 Vcb = NULL;
1550 _SEH2_LEAVE;
1551 }
1552
1553 DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
1554
1555 /* initialize Vcb structure */
1556 Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
1557 TargetDeviceObject,
1558 VolumeDeviceObject, Vpb);
1559
1560 if (NT_SUCCESS(Status)) {
1561
1562 PLIST_ENTRY List;
1563
1564 ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
1565 GlobalDataResourceAcquired = TRUE;
1566
1567 for (List = Ext2Global->VcbList.Flink;
1568 List != &Ext2Global->VcbList;
1569 List = List->Flink) {
1570
1571 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
1572 OldVpb = OldVcb->Vpb;
1573
1574 /* in case we are already in the queue, should not happen */
1575 if (OldVpb == Vpb) {
1576 continue;
1577 }
1578
1579 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
1580 (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
1581 (OldVpb->RealDevice == TargetDeviceObject) &&
1582 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
1583 (RtlEqualMemory(&OldVpb->VolumeLabel[0],
1584 &Vpb->VolumeLabel[0],
1585 Vpb->VolumeLabelLength)) &&
1586 (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
1587 &Vcb->SuperBlock->s_uuid[0], 16)) ) {
1588 ClearFlag(OldVcb->Flags, VCB_MOUNTED);
1589 }
1590 }
1591
1592 SetLongFlag(Vcb->Flags, VCB_MOUNTED);
1593 SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
1594 Ext2InsertVcb(Vcb);
1595 Vcb = NULL;
1596 Vpb = NULL;
1597 ObDereferenceObject(TargetDeviceObject);
1598
1599 } else {
1600
1601 Vcb = NULL;
1602 }
1603
1604 } _SEH2_FINALLY {
1605
1606 if (GlobalDataResourceAcquired) {
1607 ExReleaseResourceLite(&Ext2Global->Resource);
1608 }
1609
1610 if (!NT_SUCCESS(Status)) {
1611
1612 if (!NT_SUCCESS(Status)) {
1613 if ( Vpb != NULL ) {
1614 Vpb->DeviceObject = NULL;
1615 }
1616 }
1617
1618 if (Vcb) {
1619 Ext2DestroyVcb(Vcb);
1620 } else {
1621 if (Ext2Sb) {
1622 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
1623 }
1624 if (VolumeDeviceObject) {
1625 IoDeleteDevice(VolumeDeviceObject);
1626 DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
1627 }
1628 }
1629 }
1630
1631 if (!IrpContext->ExceptionInProgress) {
1632 Ext2CompleteIrpContext(IrpContext, Status);
1633 }
1634 } _SEH2_END;
1635
1636 return Status;
1637 }
1638
1639 VOID
1640 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
1641 IN PEXT2_VCB Vcb )
1642 {
1643 NTSTATUS Status = STATUS_SUCCESS;
1644
1645 BOOLEAN bVerify = FALSE;
1646 ULONG ChangeCount = 0;
1647 ULONG dwBytes;
1648
1649 PIRP Irp;
1650 PEXTENDED_IO_STACK_LOCATION IrpSp;
1651
1652 _SEH2_TRY {
1653
1654 ASSERT(IrpContext != NULL);
1655
1656 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1657 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1658
1659 Irp = IrpContext->Irp;
1660 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
1661
1662 bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1663
1664 if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
1665 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
1666
1667 dwBytes = sizeof(ULONG);
1668 Status = Ext2DiskIoControl(
1669 Vcb->TargetDeviceObject,
1670 IOCTL_DISK_CHECK_VERIFY,
1671 NULL,
1672 0,
1673 &ChangeCount,
1674 &dwBytes );
1675
1676 if ( STATUS_VERIFY_REQUIRED == Status ||
1677 STATUS_DEVICE_NOT_READY == Status ||
1678 STATUS_NO_MEDIA_IN_DEVICE == Status ||
1679 (NT_SUCCESS(Status) &&
1680 (ChangeCount != Vcb->ChangeCount))) {
1681
1682 KIRQL Irql;
1683
1684 IoAcquireVpbSpinLock(&Irql);
1685 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
1686 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1687 }
1688 IoReleaseVpbSpinLock(Irql);
1689
1690 } else {
1691
1692 if (!NT_SUCCESS(Status)) {
1693 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
1694 }
1695 }
1696 }
1697
1698 if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
1699 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
1700 Ext2NormalizeAndRaiseStatus ( IrpContext,
1701 STATUS_VERIFY_REQUIRED );
1702 }
1703
1704 if (IsMounted(Vcb)) {
1705
1706 if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
1707 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
1708 (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
1709 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
1710 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
1711 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1712 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
1713 IrpSp->Parameters.FileSystemControl.FsControlCode ==
1714 FSCTL_MARK_VOLUME_DIRTY)) {
1715
1716 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
1717
1718 KIRQL Irql;
1719
1720 IoAcquireVpbSpinLock(&Irql);
1721 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
1722 SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1723 }
1724 IoReleaseVpbSpinLock(Irql);
1725
1726 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
1727
1728 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
1729 }
1730 }
1731 }
1732
1733 } _SEH2_FINALLY {
1734
1735 } _SEH2_END;
1736
1737 }
1738
1739
1740 NTSTATUS
1741 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
1742 {
1743 PDEVICE_OBJECT DeviceObject;
1744 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1745 PEXT2_SUPER_BLOCK ext2_sb = NULL;
1746 PEXT2_VCB Vcb = NULL;
1747 BOOLEAN VcbResourceAcquired = FALSE;
1748 PIRP Irp;
1749 ULONG ChangeCount = 0;
1750 ULONG dwBytes;
1751
1752 _SEH2_TRY {
1753
1754 ASSERT(IrpContext != NULL);
1755 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1756 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1757
1758 DeviceObject = IrpContext->DeviceObject;
1759 //
1760 // This request is not allowed on the main device object
1761 //
1762 if (IsExt2FsDevice(DeviceObject)) {
1763 Status = STATUS_INVALID_DEVICE_REQUEST;
1764 _SEH2_LEAVE;
1765 }
1766
1767 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1768 ASSERT(Vcb != NULL);
1769 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1770 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1771
1772 VcbResourceAcquired =
1773 ExAcquireResourceExclusiveLite(
1774 &Vcb->MainResource,
1775 TRUE );
1776
1777 if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
1778 Status = STATUS_SUCCESS;
1779 _SEH2_LEAVE;
1780 }
1781
1782 if (!IsMounted(Vcb)) {
1783 Status = STATUS_WRONG_VOLUME;
1784 _SEH2_LEAVE;
1785 }
1786
1787 dwBytes = sizeof(ULONG);
1788 Status = Ext2DiskIoControl(
1789 Vcb->TargetDeviceObject,
1790 IOCTL_DISK_CHECK_VERIFY,
1791 NULL,
1792 0,
1793 &ChangeCount,
1794 &dwBytes );
1795
1796
1797 if (!NT_SUCCESS(Status)) {
1798 Status = STATUS_WRONG_VOLUME;
1799 _SEH2_LEAVE;
1800 } else {
1801 Vcb->ChangeCount = ChangeCount;
1802 }
1803
1804 Irp = IrpContext->Irp;
1805
1806 Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
1807
1808 if (!NT_SUCCESS(Status)) {
1809 _SEH2_LEAVE;
1810 }
1811
1812 ASSERT(NULL != ext2_sb);
1813 if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
1814 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
1815 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
1816
1817 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
1818
1819 if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
1820 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
1821 } else {
1822 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
1823 }
1824
1825 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
1826
1827 } else {
1828
1829 Status = STATUS_WRONG_VOLUME;
1830 if (VcbResourceAcquired) {
1831 ExReleaseResourceLite(&Vcb->MainResource);
1832 VcbResourceAcquired = FALSE;
1833 }
1834 Ext2PurgeVolume(Vcb, FALSE);
1835 VcbResourceAcquired =
1836 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
1837
1838 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
1839 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
1840
1841 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
1842 }
1843
1844 } _SEH2_FINALLY {
1845
1846 if (ext2_sb)
1847 Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
1848
1849 if (VcbResourceAcquired) {
1850 ExReleaseResourceLite(&Vcb->MainResource);
1851 }
1852
1853 if (!IrpContext->ExceptionInProgress) {
1854 Ext2CompleteIrpContext(IrpContext, Status);
1855 }
1856 } _SEH2_END;
1857
1858 return Status;
1859 }
1860
1861
1862 NTSTATUS
1863 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
1864 {
1865 PDEVICE_OBJECT DeviceObject;
1866 PEXT2_VCB Vcb = 0;
1867 NTSTATUS Status = STATUS_SUCCESS;
1868
1869 ASSERT(IrpContext);
1870
1871 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1872 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1873
1874
1875 DeviceObject = IrpContext->DeviceObject;
1876
1877 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1878
1879 ASSERT(IsMounted(Vcb));
1880
1881 Ext2VerifyVcb (IrpContext, Vcb);
1882
1883 Ext2CompleteIrpContext(IrpContext, Status);
1884
1885 return Status;
1886 }
1887
1888
1889 NTSTATUS
1890 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
1891 {
1892 PDEVICE_OBJECT DeviceObject;
1893 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1894 PEXT2_VCB Vcb;
1895 BOOLEAN VcbResourceAcquired = FALSE;
1896
1897 _SEH2_TRY {
1898
1899 ASSERT(IrpContext != NULL);
1900
1901 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1902 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1903
1904 DeviceObject = IrpContext->DeviceObject;
1905
1906 //
1907 // This request is not allowed on the main device object
1908 //
1909 if (IsExt2FsDevice(DeviceObject)) {
1910 Status = STATUS_INVALID_DEVICE_REQUEST;
1911 _SEH2_LEAVE;
1912 }
1913
1914 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1915
1916 ASSERT(Vcb != NULL);
1917
1918 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1919 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1920
1921 ASSERT(IsMounted(Vcb));
1922
1923 ExAcquireResourceExclusiveLite(
1924 &Vcb->MainResource,
1925 TRUE );
1926
1927 VcbResourceAcquired = TRUE;
1928
1929 if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
1930 Status = STATUS_VOLUME_DISMOUNTED;
1931 _SEH2_LEAVE;
1932 }
1933
1934 Ext2FlushFiles(IrpContext, Vcb, FALSE);
1935 Ext2FlushVolume(IrpContext, Vcb, FALSE);
1936
1937 ExReleaseResourceLite(&Vcb->MainResource);
1938 VcbResourceAcquired = FALSE;
1939
1940 Ext2PurgeVolume(Vcb, TRUE);
1941 Ext2CheckDismount(IrpContext, Vcb, TRUE);
1942
1943 DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
1944 Status = STATUS_SUCCESS;
1945
1946 } _SEH2_FINALLY {
1947
1948 if (VcbResourceAcquired) {
1949 ExReleaseResourceLite(&Vcb->MainResource);
1950 }
1951
1952 if (!IrpContext->ExceptionInProgress) {
1953 Ext2CompleteIrpContext(IrpContext, Status);
1954 }
1955 } _SEH2_END;
1956
1957 return Status;
1958 }
1959
1960 BOOLEAN
1961 Ext2CheckDismount (
1962 IN PEXT2_IRP_CONTEXT IrpContext,
1963 IN PEXT2_VCB Vcb,
1964 IN BOOLEAN bForce )
1965 {
1966 KIRQL Irql;
1967 PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
1968 BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
1969 ULONG UnCleanCount = 0;
1970
1971 NewVpb = Ext2AllocatePool(NonPagedPool, VPB_SIZE, TAG_VPB);
1972 if (NewVpb == NULL) {
1973 DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
1974 return FALSE;
1975 }
1976 INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
1977 memset(NewVpb, '_', VPB_SIZE);
1978 RtlZeroMemory(NewVpb, sizeof(VPB));
1979
1980 ExAcquireResourceExclusiveLite(
1981 &Ext2Global->Resource, TRUE );
1982
1983 ExAcquireResourceExclusiveLite(
1984 &Vcb->MainResource, TRUE );
1985
1986 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
1987 (IrpContext->RealDevice == Vcb->RealDevice)) {
1988 UnCleanCount = 3;
1989 } else {
1990 UnCleanCount = 2;
1991 }
1992
1993 IoAcquireVpbSpinLock (&Irql);
1994
1995 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
1996 Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
1997 if (Vpb->ReferenceCount <= UnCleanCount) {
1998
1999 if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2000
2001 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2002 ClearFlag(Vpb->Flags, VPB_LOCKED);
2003
2004 if ((Vcb->RealDevice != Vpb->RealDevice) &&
2005 (Vcb->RealDevice->Vpb == Vpb)) {
2006 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
2007 SetFlag(Vpb->Flags, VPB_PERSISTENT );
2008 }
2009
2010 Ext2RemoveVcb(Vcb);
2011 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2012 }
2013
2014 if (Vpb->ReferenceCount) {
2015 bTearDown = TRUE;
2016 } else {
2017 bDeleted = TRUE;
2018 Vpb->DeviceObject = NULL;
2019 }
2020
2021 } else if (bForce) {
2022
2023 DEBUG(DL_DBG, ( "Ext2CheckDismount: NewVpb %p Realdevice = %p\n",
2024 NewVpb, Vpb->RealDevice));
2025
2026 Vcb->Vpb2 = Vcb->Vpb;
2027 NewVpb->Type = IO_TYPE_VPB;
2028 NewVpb->Size = sizeof(VPB);
2029 NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
2030 NewVpb->RealDevice = Vpb->RealDevice;
2031 NewVpb->RealDevice->Vpb = NewVpb;
2032 NewVpb = NULL;
2033 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2034 SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
2035 ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
2036 }
2037
2038 IoReleaseVpbSpinLock(Irql);
2039
2040 ExReleaseResourceLite(&Vcb->MainResource);
2041 ExReleaseResourceLite(&Ext2Global->Resource);
2042
2043 if (bTearDown) {
2044 DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
2045 Ext2TearDownStream(Vcb);
2046 }
2047
2048 if (bDeleted) {
2049 DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
2050 Ext2DestroyVcb(Vcb);
2051 }
2052
2053 if (NewVpb != NULL) {
2054 DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing Vpb %p\n", NewVpb));
2055 Ext2FreePool(NewVpb, TAG_VPB);
2056 DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2057 }
2058
2059 return bDeleted;
2060 }
2061
2062 NTSTATUS
2063 Ext2PurgeVolume (IN PEXT2_VCB Vcb,
2064 IN BOOLEAN FlushBeforePurge )
2065 {
2066 PEXT2_FCB Fcb;
2067 LIST_ENTRY FcbList;
2068 PLIST_ENTRY ListEntry;
2069 PFCB_LIST_ENTRY FcbListEntry;
2070 BOOLEAN VcbResourceAcquired = FALSE;
2071 _SEH2_TRY {
2072
2073 ASSERT(Vcb != NULL);
2074 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2075 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2076
2077 VcbResourceAcquired =
2078 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2079
2080 if (IsVcbReadOnly(Vcb)) {
2081 FlushBeforePurge = FALSE;
2082 }
2083
2084 Ext2PutGroup(Vcb);
2085
2086 FcbListEntry= NULL;
2087 InitializeListHead(&FcbList);
2088
2089 for (ListEntry = Vcb->FcbList.Flink;
2090 ListEntry != &Vcb->FcbList;
2091 ListEntry = ListEntry->Flink ) {
2092
2093 Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
2094
2095 DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", &Fcb->Mcb->FullName, Fcb->ReferenceCount));
2096
2097 FcbListEntry = Ext2AllocatePool(
2098 PagedPool,
2099 sizeof(FCB_LIST_ENTRY),
2100 EXT2_FLIST_MAGIC
2101 );
2102
2103 if (FcbListEntry) {
2104 FcbListEntry->Fcb = Fcb;
2105 Ext2ReferXcb(&Fcb->ReferenceCount);
2106 InsertTailList(&FcbList, &FcbListEntry->Next);
2107 } else {
2108 DEBUG(DL_ERR, ( "Ext2PurgeVolume: failed to allocate FcbListEntry ...\n"));
2109 }
2110 }
2111
2112 while (!IsListEmpty(&FcbList)) {
2113
2114 ListEntry = RemoveHeadList(&FcbList);
2115
2116 FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
2117
2118 Fcb = FcbListEntry->Fcb;
2119
2120 if (ExAcquireResourceExclusiveLite(
2121 &Fcb->MainResource,
2122 TRUE )) {
2123
2124 Ext2PurgeFile(Fcb, FlushBeforePurge);
2125
2126 if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
2127 Ext2FreeFcb(Fcb);
2128 } else {
2129 ExReleaseResourceLite(&Fcb->MainResource);
2130 }
2131 }
2132
2133 Ext2FreePool(FcbListEntry, EXT2_FLIST_MAGIC);
2134 }
2135
2136 if (FlushBeforePurge) {
2137 ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
2138 ExReleaseResourceLite(&Vcb->PagingIoResource);
2139
2140 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
2141 }
2142
2143 if (Vcb->SectionObject.ImageSectionObject) {
2144 MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
2145 }
2146
2147 if (VcbResourceAcquired) {
2148 ExReleaseResourceLite(&Vcb->MainResource);
2149 VcbResourceAcquired = FALSE;
2150 }
2151
2152 if (Vcb->SectionObject.DataSectionObject) {
2153 CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
2154 }
2155
2156 DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
2157
2158 } _SEH2_FINALLY {
2159
2160 if (VcbResourceAcquired) {
2161 ExReleaseResourceLite(&Vcb->MainResource);
2162 }
2163 } _SEH2_END;
2164
2165 return STATUS_SUCCESS;
2166 }
2167
2168 NTSTATUS
2169 Ext2PurgeFile ( IN PEXT2_FCB Fcb,
2170 IN BOOLEAN FlushBeforePurge )
2171 {
2172 IO_STATUS_BLOCK IoStatus;
2173
2174 ASSERT(Fcb != NULL);
2175
2176 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
2177 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
2178
2179
2180 if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
2181
2182 DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
2183 &Fcb->Mcb->FullName));
2184
2185 ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
2186 ExReleaseResourceLite(&Fcb->PagingIoResource);
2187
2188 CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
2189 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
2190 }
2191
2192 if (Fcb->SectionObject.ImageSectionObject) {
2193
2194 DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
2195 &Fcb->Mcb->FullName));
2196
2197 MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
2198 }
2199
2200 if (Fcb->SectionObject.DataSectionObject) {
2201
2202 DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
2203 &Fcb->Mcb->FullName));
2204
2205 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
2206 }
2207
2208 return STATUS_SUCCESS;
2209 }
2210
2211
2212 NTSTATUS
2213 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
2214 {
2215 NTSTATUS Status;
2216
2217 ASSERT(IrpContext);
2218
2219 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2220 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2221
2222 switch (IrpContext->MinorFunction) {
2223
2224 case IRP_MN_USER_FS_REQUEST:
2225 Status = Ext2UserFsRequest(IrpContext);
2226 break;
2227
2228 case IRP_MN_MOUNT_VOLUME:
2229 Status = Ext2MountVolume(IrpContext);
2230 break;
2231
2232 case IRP_MN_VERIFY_VOLUME:
2233 Status = Ext2VerifyVolume(IrpContext);
2234 break;
2235
2236 default:
2237
2238 DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
2239 Status = STATUS_INVALID_DEVICE_REQUEST;
2240 Ext2CompleteIrpContext(IrpContext, Status);
2241 }
2242
2243 return Status;
2244 }