xref: /reactos/drivers/filesystems/ext2/src/fsctl.c (revision 8a978a17)
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 = NULL;
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 = NULL;
246     PDEVICE_OBJECT  DeviceObject = NULL;
247     PEXT2_VCB       Vcb = NULL;
248     NTSTATUS        Status;
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 NTSTATUS
1293 Ext2InspectReparseData(
1294     IN PREPARSE_DATA_BUFFER RDB,
1295     IN ULONG InputBufferLength
1296 )
1297 {
1298     NTSTATUS Status = STATUS_SUCCESS;
1299 
1300     if (!RDB) {
1301         Status = STATUS_INVALID_PARAMETER;
1302         goto out;
1303     }
1304 
1305     if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
1306         Status = STATUS_BUFFER_OVERFLOW;
1307         goto out;
1308     }
1309 
1310     if (InputBufferLength < RDB->ReparseDataLength) {
1311         Status = STATUS_BUFFER_OVERFLOW;
1312         goto out;
1313     }
1314 
1315     if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
1316         Status = STATUS_NOT_IMPLEMENTED;
1317         goto out;
1318     }
1319 
1320     if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
1321           + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
1322           + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
1323         > (PUCHAR)RDB + InputBufferLength ) {
1324         Status = STATUS_BUFFER_OVERFLOW;
1325         goto out;
1326     }
1327 
1328     if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
1329           + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
1330           + RDB->SymbolicLinkReparseBuffer.PrintNameLength
1331         > (PUCHAR)RDB + InputBufferLength) {
1332         Status = STATUS_BUFFER_OVERFLOW;
1333         goto out;
1334     }
1335 
1336     if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
1337         Status = STATUS_NOT_IMPLEMENTED;
1338         goto out;
1339     }
1340 
1341 out:
1342     return Status;
1343 }
1344 
1345 VOID
1346 Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
1347 {
1348     ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
1349            REPARSE_DATA_BUFFER_HEADER_SIZE);
1350     RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
1351     RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
1352                              FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
1353                              PathBufferLength * sizeof(WCHAR);
1354     RDB->Reserved = 0;
1355     RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
1356     RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
1357     RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
1358     RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
1359     RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
1360     RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
1361 }
1362 
1363 NTSTATUS
1364 Ext2ReadSymlink (
1365     IN PEXT2_IRP_CONTEXT    IrpContext,
1366     IN PEXT2_VCB            Vcb,
1367     IN PEXT2_MCB            Mcb,
1368     IN PVOID                Buffer,
1369     IN ULONG                Size,
1370     OUT PULONG              BytesRead
1371     )
1372 {
1373     return Ext2ReadInode (  IrpContext,
1374                             Vcb,
1375                             Mcb,
1376                             0,
1377                             Buffer,
1378                             Size,
1379                             FALSE,
1380                             BytesRead);
1381 }
1382 
1383 
1384 
1385 NTSTATUS
1386 Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1387 {
1388     PIRP                        Irp = NULL;
1389     PIO_STACK_LOCATION          IrpSp;
1390     PEXTENDED_IO_STACK_LOCATION EIrpSp;
1391 
1392     PDEVICE_OBJECT      DeviceObject;
1393 
1394     PEXT2_VCB           Vcb = NULL;
1395     PEXT2_CCB           Ccb = NULL;
1396     PEXT2_MCB           Mcb = NULL;
1397 
1398     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
1399     BOOLEAN             MainResourceAcquired = FALSE;
1400 
1401     PVOID               OutputBuffer;
1402     ULONG               OutputBufferLength;
1403     ULONG               BytesRead = 0;
1404 
1405     PREPARSE_DATA_BUFFER RDB;
1406 
1407     UNICODE_STRING  UniName;
1408     OEM_STRING      OemName;
1409 
1410     PCHAR           OemNameBuffer = NULL;
1411     int             OemNameLength = 0, i;
1412 
1413     Ccb = IrpContext->Ccb;
1414     ASSERT(Ccb != NULL);
1415     ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1416            (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1417     DeviceObject = IrpContext->DeviceObject;
1418     Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1419     Mcb = IrpContext->Fcb->Mcb;
1420     Irp = IrpContext->Irp;
1421     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1422 
1423     _SEH2_TRY {
1424 
1425         if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
1426             !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
1427             Status = STATUS_NOT_A_REPARSE_POINT;
1428             _SEH2_LEAVE;
1429         }
1430 
1431         OutputBuffer  = (PVOID)Irp->AssociatedIrp.SystemBuffer;
1432         OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
1433 
1434         RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
1435         if (!RDB) {
1436             Status = STATUS_INVALID_PARAMETER;
1437             _SEH2_LEAVE;
1438         }
1439         if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
1440             Status = STATUS_BUFFER_OVERFLOW;
1441             _SEH2_LEAVE;
1442         }
1443 
1444         OemNameLength = (ULONG)Mcb->Inode.i_size;
1445         if (OemNameLength > USHRT_MAX) {
1446             Status = STATUS_INVALID_PARAMETER;
1447             _SEH2_LEAVE;
1448         }
1449         OemName.Length = (USHORT)OemNameLength;
1450         OemName.MaximumLength = OemNameLength + 1;
1451         OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
1452                                           OemName.MaximumLength,
1453                                           'NL2E');
1454         if (!OemNameBuffer) {
1455             Status = STATUS_INSUFFICIENT_RESOURCES;
1456             _SEH2_LEAVE;
1457         }
1458 
1459         Status = Ext2ReadSymlink(IrpContext,
1460                                  Vcb,
1461                                  Mcb,
1462                                  OemNameBuffer,
1463                                  OemNameLength,
1464                                  &BytesRead
1465                                 );
1466         OemName.Buffer[OemName.Length] = '\0';
1467         for (i = 0;i < OemName.Length;i++) {
1468             if (OemName.Buffer[i] == '/') {
1469                 OemName.Buffer[i] = '\\';
1470             }
1471         }
1472 
1473         if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
1474             UniName.Length = USHRT_MAX;
1475         } else {
1476             UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
1477         }
1478         UniName.MaximumLength = UniName.Length;
1479         UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
1480         Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
1481         if (UniName.MaximumLength < 2*UniName.Length) {
1482             Status = STATUS_BUFFER_TOO_SMALL;
1483             _SEH2_LEAVE;
1484         }
1485 
1486         Ext2InitializeReparseData(RDB, UniName.Length);
1487         UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
1488         /*
1489             (PWCHAR)((PUCHAR)&
1490              + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1491          */
1492         Ext2OEMToUnicode(Vcb, &UniName, &OemName);
1493         RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
1494                                RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
1495                        UniName.Buffer, UniName.Length);
1496 
1497         Status = STATUS_SUCCESS;
1498 
1499     } _SEH2_FINALLY {
1500 
1501         if (OemNameBuffer) {
1502             Ext2FreePool(OemNameBuffer, 'NL2E');
1503         }
1504 
1505         if (!_SEH2_AbnormalTermination()) {
1506             if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1507                 Status = Ext2QueueRequest(IrpContext);
1508             } else {
1509                 Ext2CompleteIrpContext(IrpContext, Status);
1510             }
1511         }
1512     } _SEH2_END;
1513 
1514     return Status;
1515 }
1516 
1517 
1518 NTSTATUS
1519 Ext2WriteSymlink (
1520     IN PEXT2_IRP_CONTEXT    IrpContext,
1521     IN PEXT2_VCB            Vcb,
1522     IN PEXT2_MCB            Mcb,
1523     IN PVOID                Buffer,
1524     IN ULONG                Size,
1525     OUT PULONG              BytesWritten
1526 )
1527 {
1528     NTSTATUS Status = STATUS_SUCCESS;
1529     PUCHAR   Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
1530 
1531     if (Size >= EXT2_LINKLEN_IN_INODE) {
1532 
1533         /* initialize inode i_block[] */
1534         if (0 == Mcb->Inode.i_blocks) {
1535             memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1536             ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1537             Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1538         }
1539 
1540         Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
1541                                 0, Buffer, Size,
1542                                 FALSE, BytesWritten);
1543         if (!NT_SUCCESS(Status)) {
1544             goto out;
1545         }
1546 
1547     } else {
1548 
1549         /* free inode blocks before writing in line */
1550         if (Mcb->Inode.i_blocks) {
1551             LARGE_INTEGER Zero = {0, 0};
1552             Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
1553         }
1554 
1555         ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1556         memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1557         RtlCopyMemory(Data, Buffer, Size);
1558     }
1559 
1560     Mcb->Inode.i_size = Size;
1561     Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1562 
1563     if (BytesWritten) {
1564         *BytesWritten = Size;
1565     }
1566 
1567 out:
1568     return Status;
1569 }
1570 
1571 NTSTATUS
1572 Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1573 {
1574     PIRP                Irp = NULL;
1575     PIO_STACK_LOCATION  IrpSp;
1576 
1577     PDEVICE_OBJECT      DeviceObject;
1578 
1579     PEXT2_VCB           Vcb = NULL;
1580     PEXT2_FCB           Fcb = NULL;
1581     PEXT2_CCB           Ccb = NULL;
1582     PEXT2_MCB           Mcb = NULL;
1583 
1584     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
1585 
1586     PVOID               InputBuffer;
1587     ULONG               InputBufferLength;
1588     ULONG               BytesWritten = 0;
1589 
1590     PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
1591     PEXT2_MCB           ParentMcb = NULL;
1592 
1593     PREPARSE_DATA_BUFFER RDB;
1594 
1595     UNICODE_STRING      UniName;
1596     OEM_STRING          OemName;
1597 
1598     PCHAR               OemNameBuffer = NULL;
1599     int                 OemNameLength = 0, i;
1600 
1601     BOOLEAN             MainResourceAcquired = FALSE;
1602     BOOLEAN             FcbLockAcquired = FALSE;
1603 
1604     _SEH2_TRY {
1605 
1606         Ccb = IrpContext->Ccb;
1607         ASSERT(Ccb != NULL);
1608         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1609                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1610         DeviceObject = IrpContext->DeviceObject;
1611         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1612         Fcb = IrpContext->Fcb;
1613         Mcb = Fcb->Mcb;
1614         Irp = IrpContext->Irp;
1615         IrpSp = IoGetCurrentIrpStackLocation(Irp);
1616 
1617         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
1618         FcbLockAcquired = TRUE;
1619 
1620         ParentMcb = Mcb->Parent;
1621         ParentDcb = ParentMcb->Fcb;
1622         if (ParentDcb == NULL) {
1623             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1624         }
1625         if (ParentDcb) {
1626             Ext2ReferXcb(&ParentDcb->ReferenceCount);
1627         }
1628 
1629         if (!Mcb)
1630             _SEH2_LEAVE;
1631 
1632         if (FcbLockAcquired) {
1633             ExReleaseResourceLite(&Vcb->FcbLock);
1634             FcbLockAcquired = FALSE;
1635         }
1636 
1637         if (!ExAcquireResourceSharedLite(
1638                     &Fcb->MainResource,
1639                     IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
1640             Status = STATUS_PENDING;
1641             _SEH2_LEAVE;
1642         }
1643         MainResourceAcquired = TRUE;
1644 
1645         InputBuffer  = Irp->AssociatedIrp.SystemBuffer;
1646         InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
1647 
1648         RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
1649         Status = Ext2InspectReparseData(RDB, InputBufferLength);
1650         if (!NT_SUCCESS(Status)) {
1651             _SEH2_LEAVE;
1652         }
1653 
1654         UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
1655         UniName.MaximumLength = UniName.Length;
1656         UniName.Buffer =
1657             (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
1658              + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1659 
1660         OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
1661         if (OemNameLength > USHRT_MAX) {
1662             Status = STATUS_INVALID_PARAMETER;
1663             _SEH2_LEAVE;
1664         }
1665         OemName.Length = (USHORT)OemNameLength;
1666         OemName.MaximumLength = OemNameLength + 1;
1667         OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
1668                                           OemName.MaximumLength,
1669                                           'NL2E');
1670         if (!OemNameBuffer) {
1671             Status = STATUS_INSUFFICIENT_RESOURCES;
1672             _SEH2_LEAVE;
1673         }
1674 
1675         Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
1676         OemName.Buffer[OemName.Length] = '\0';
1677         for (i = 0;i < OemName.Length;i++) {
1678             if (OemName.Buffer[i] == '\\') {
1679                 OemName.Buffer[i] = '/';
1680             }
1681         }
1682 
1683         /* free all data blocks of the inode (to be set as symlink) */
1684         {
1685             LARGE_INTEGER zero = {0};
1686             Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
1687         }
1688 
1689         /* decrease dir count of group desc and vcb stat */
1690         if (S_ISDIR(Mcb->Inode.i_mode)) {
1691 
1692             ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
1693             Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
1694 
1695             /* drop extra reference for dir inode */
1696             ext3_dec_count(&Mcb->Inode);
1697         }
1698 
1699         /* overwrite inode mode as type SYMLINK */
1700         Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1701         SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
1702 
1703         Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
1704                                   OemNameLength, &BytesWritten);
1705         if (NT_SUCCESS(Status)) {
1706             Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
1707                             S_IFLNK | S_IRWXUGO);
1708         }
1709 
1710     } _SEH2_FINALLY {
1711 
1712         if (FcbLockAcquired) {
1713             ExReleaseResourceLite(&Vcb->FcbLock);
1714             FcbLockAcquired = FALSE;
1715         }
1716 
1717         if (MainResourceAcquired) {
1718             ExReleaseResourceLite(&Fcb->MainResource);
1719         }
1720 
1721         if (OemNameBuffer) {
1722             Ext2FreePool(OemNameBuffer, 'NL2E');
1723         }
1724 
1725         if (NT_SUCCESS(Status)) {
1726             Ext2NotifyReportChange(
1727                 IrpContext,
1728                 Vcb,
1729                 Mcb,
1730                 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1731                 FILE_ACTION_MODIFIED );
1732         }
1733 
1734         if (!_SEH2_AbnormalTermination()) {
1735             if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1736                 Status = Ext2QueueRequest(IrpContext);
1737             } else {
1738                 Ext2CompleteIrpContext(IrpContext, Status);
1739             }
1740         }
1741 
1742         if (ParentDcb) {
1743             Ext2ReleaseFcb(ParentDcb);
1744         }
1745     } _SEH2_END;
1746 
1747     return Status;
1748 }
1749 
1750 NTSTATUS
1751 Ext2TruncateSymlink(
1752     PEXT2_IRP_CONTEXT IrpContext,
1753     PEXT2_VCB         Vcb,
1754     PEXT2_MCB         Mcb,
1755     ULONG             Size
1756     )
1757 {
1758     NTSTATUS status = STATUS_SUCCESS;
1759     PUCHAR   data = (PUCHAR)&Mcb->Inode.i_block;
1760     ULONG    len = (ULONG)Mcb->Inode.i_size;
1761     LARGE_INTEGER NewSize;
1762 
1763     if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
1764 
1765         RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
1766         Mcb->Inode.i_size = Size;
1767         Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1768 
1769     } else {
1770         NewSize.QuadPart = Size;
1771         status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
1772         if (!NT_SUCCESS(status)) {
1773             goto out;
1774         }
1775     }
1776 
1777 out:
1778     return status;
1779 }
1780 
1781 
1782 /* FIXME: We can only handle one reparse point right now. */
1783 NTSTATUS
1784 Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1785 {
1786     PIRP                        Irp = NULL;
1787 
1788     PDEVICE_OBJECT      DeviceObject;
1789 
1790     PEXT2_VCB           Vcb = NULL;
1791     PEXT2_FCB           Fcb = NULL;
1792     PEXT2_CCB           Ccb = NULL;
1793     PEXT2_MCB           Mcb = NULL;
1794 
1795     PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
1796     PEXT2_MCB           ParentMcb = NULL;
1797 
1798     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
1799 
1800     BOOLEAN             FcbLockAcquired = FALSE;
1801     BOOLEAN             MainResourceAcquired = FALSE;
1802 
1803 
1804     _SEH2_TRY {
1805 
1806         Ccb = IrpContext->Ccb;
1807         ASSERT(Ccb != NULL);
1808         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1809                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1810         DeviceObject = IrpContext->DeviceObject;
1811         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1812         Mcb = IrpContext->Fcb->Mcb;
1813         Irp = IrpContext->Irp;
1814 
1815         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
1816         FcbLockAcquired = TRUE;
1817 
1818         ParentMcb = Mcb->Parent;
1819         ParentDcb = ParentMcb->Fcb;
1820         if (ParentDcb == NULL) {
1821             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1822         }
1823         if (ParentDcb) {
1824             Ext2ReferXcb(&ParentDcb->ReferenceCount);
1825         }
1826 
1827         if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
1828             !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
1829             Status = STATUS_NOT_A_REPARSE_POINT;
1830             _SEH2_LEAVE;
1831         }
1832 
1833         Fcb = Ext2AllocateFcb (Vcb, Mcb);
1834         if (Fcb) {
1835             Ext2ReferXcb(&Fcb->ReferenceCount);
1836         } else {
1837             Status = STATUS_INSUFFICIENT_RESOURCES;
1838             _SEH2_LEAVE;
1839         }
1840 
1841         if (FcbLockAcquired) {
1842             ExReleaseResourceLite(&Vcb->FcbLock);
1843             FcbLockAcquired = FALSE;
1844         }
1845 
1846         if (!ExAcquireResourceSharedLite(
1847                     &Fcb->MainResource,
1848                     IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
1849             Status = STATUS_PENDING;
1850             _SEH2_LEAVE;
1851         }
1852         MainResourceAcquired = TRUE;
1853 
1854         Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
1855         if (!NT_SUCCESS(Status)) {
1856             _SEH2_LEAVE;
1857         }
1858 
1859         /* inode is to be removed */
1860         SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
1861 
1862     } _SEH2_FINALLY {
1863 
1864         if (FcbLockAcquired) {
1865             ExReleaseResourceLite(&Vcb->FcbLock);
1866         }
1867 
1868         if (MainResourceAcquired) {
1869             ExReleaseResourceLite(&Fcb->MainResource);
1870         }
1871 
1872         if (NT_SUCCESS(Status)) {
1873             Ext2NotifyReportChange(
1874                 IrpContext,
1875                 Vcb,
1876                 Mcb,
1877                 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1878                 FILE_ACTION_MODIFIED );
1879 
1880         }
1881 
1882         if (!_SEH2_AbnormalTermination()) {
1883             if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1884                 Status = Ext2QueueRequest(IrpContext);
1885             } else {
1886                 Ext2CompleteIrpContext(IrpContext, Status);
1887             }
1888         }
1889 
1890         if (ParentDcb) {
1891             Ext2ReleaseFcb(ParentDcb);
1892         }
1893 
1894         if (Fcb) {
1895             Ext2ReleaseFcb(Fcb);
1896         }
1897     } _SEH2_END;
1898 
1899     return Status;
1900 }
1901 
1902 NTSTATUS
1903 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
1904 {
1905     PIRP                Irp;
1906     PIO_STACK_LOCATION  IoStackLocation;
1907     ULONG               FsControlCode;
1908     NTSTATUS            Status;
1909 
1910     ASSERT(IrpContext);
1911 
1912     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1913            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1914 
1915     Irp = IrpContext->Irp;
1916     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1917 
1918 #ifndef _GNU_NTIFS_
1919     FsControlCode =
1920         IoStackLocation->Parameters.FileSystemControl.FsControlCode;
1921 #else
1922     FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
1923                      IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
1924 #endif
1925 
1926     switch (FsControlCode) {
1927 
1928     case FSCTL_GET_REPARSE_POINT:
1929         Status = Ext2GetReparsePoint(IrpContext);
1930         break;
1931 
1932     case FSCTL_SET_REPARSE_POINT:
1933         Status = Ext2SetReparsePoint(IrpContext);
1934         break;
1935 
1936     case FSCTL_DELETE_REPARSE_POINT:
1937         Status = Ext2DeleteReparsePoint(IrpContext);
1938         break;
1939 
1940     case FSCTL_LOCK_VOLUME:
1941         Status = Ext2LockVolume(IrpContext);
1942         break;
1943 
1944     case FSCTL_UNLOCK_VOLUME:
1945         Status = Ext2UnlockVolume(IrpContext);
1946         break;
1947 
1948     case FSCTL_DISMOUNT_VOLUME:
1949         Status = Ext2DismountVolume(IrpContext);
1950         break;
1951 
1952     case FSCTL_IS_VOLUME_MOUNTED:
1953         Status = Ext2IsVolumeMounted(IrpContext);
1954         break;
1955 
1956     case FSCTL_INVALIDATE_VOLUMES:
1957         Status = Ext2InvalidateVolumes(IrpContext);
1958         break;
1959 
1960 #if (_WIN32_WINNT >= 0x0500)
1961     case FSCTL_ALLOW_EXTENDED_DASD_IO:
1962         Status = Ext2AllowExtendedDasdIo(IrpContext);
1963         break;
1964 #endif //(_WIN32_WINNT >= 0x0500)
1965 
1966     case FSCTL_REQUEST_OPLOCK_LEVEL_1:
1967     case FSCTL_REQUEST_OPLOCK_LEVEL_2:
1968     case FSCTL_REQUEST_BATCH_OPLOCK:
1969     case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
1970     case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
1971     case FSCTL_OPLOCK_BREAK_NOTIFY:
1972     case FSCTL_OPLOCK_BREAK_ACK_NO_2:
1973 
1974         Status = Ext2OplockRequest(IrpContext);
1975         break;
1976 
1977     case FSCTL_IS_VOLUME_DIRTY:
1978         Status = Ext2IsVolumeDirty(IrpContext);
1979         break;
1980 
1981     case FSCTL_QUERY_RETRIEVAL_POINTERS:
1982         Status = Ext2QueryRetrievalPointers(IrpContext);
1983         break;
1984 
1985     case FSCTL_GET_RETRIEVAL_POINTERS:
1986         Status = Ext2GetRetrievalPointers(IrpContext);
1987         break;
1988 
1989     case FSCTL_GET_RETRIEVAL_POINTER_BASE:
1990         Status = Ext2GetRetrievalPointerBase(IrpContext);
1991         break;
1992 
1993     default:
1994 
1995         DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
1996         Status = STATUS_INVALID_DEVICE_REQUEST;
1997 
1998         Ext2CompleteIrpContext(IrpContext,  Status);
1999     }
2000 
2001     return Status;
2002 }
2003 
2004 BOOLEAN
2005 Ext2IsMediaWriteProtected (
2006     IN PEXT2_IRP_CONTEXT   IrpContext,
2007     IN PDEVICE_OBJECT TargetDevice
2008 )
2009 {
2010     PIRP            Irp;
2011     KEVENT          Event;
2012     NTSTATUS        Status;
2013     IO_STATUS_BLOCK IoStatus;
2014 
2015     KeInitializeEvent(&Event, NotificationEvent, FALSE);
2016 
2017     Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
2018                                          TargetDevice,
2019                                          NULL,
2020                                          0,
2021                                          NULL,
2022                                          0,
2023                                          FALSE,
2024                                          &Event,
2025                                          &IoStatus );
2026 
2027     if (Irp == NULL) {
2028         return FALSE;
2029     }
2030 
2031     SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
2032 
2033     Status = IoCallDriver(TargetDevice, Irp);
2034 
2035     if (Status == STATUS_PENDING) {
2036 
2037         (VOID) KeWaitForSingleObject( &Event,
2038                                       Executive,
2039                                       KernelMode,
2040                                       FALSE,
2041                                       (PLARGE_INTEGER)NULL );
2042 
2043         Status = IoStatus.Status;
2044     }
2045 
2046     return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
2047 }
2048 
2049 NTSTATUS
2050 Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2051 {
2052     PDEVICE_OBJECT              MainDeviceObject;
2053     BOOLEAN                     GlobalDataResourceAcquired = FALSE;
2054     PIRP                        Irp;
2055     PIO_STACK_LOCATION          IoStackLocation;
2056     PDEVICE_OBJECT              TargetDeviceObject;
2057     NTSTATUS                    Status = STATUS_UNRECOGNIZED_VOLUME;
2058     PDEVICE_OBJECT              VolumeDeviceObject = NULL;
2059     PEXT2_VCB                   Vcb = NULL, OldVcb = NULL;
2060     PVPB                        OldVpb = NULL, Vpb = NULL;
2061     PEXT2_SUPER_BLOCK           Ext2Sb = NULL;
2062     ULONG                       dwBytes;
2063     DISK_GEOMETRY               DiskGeometry;
2064 
2065     _SEH2_TRY {
2066 
2067         ASSERT(IrpContext != NULL);
2068         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2069                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2070 
2071         MainDeviceObject = IrpContext->DeviceObject;
2072 
2073         //
2074         //  Make sure we can wait.
2075         //
2076 
2077         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2078 
2079         //
2080         // This request is only allowed on the main device object
2081         //
2082         if (!IsExt2FsDevice(MainDeviceObject)) {
2083             Status = STATUS_INVALID_DEVICE_REQUEST;
2084             _SEH2_LEAVE;
2085         }
2086 
2087         if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
2088             Status = STATUS_UNRECOGNIZED_VOLUME;
2089             _SEH2_LEAVE;
2090         }
2091 
2092 #if 0
2093         if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
2094                 *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
2095         } else {
2096             Status = STATUS_UNRECOGNIZED_VOLUME;
2097             _SEH2_LEAVE;
2098         }
2099 #endif
2100 
2101         Irp = IrpContext->Irp;
2102         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2103         TargetDeviceObject =
2104             IoStackLocation->Parameters.MountVolume.DeviceObject;
2105 
2106         dwBytes = sizeof(DISK_GEOMETRY);
2107         Status = Ext2DiskIoControl(
2108                      TargetDeviceObject,
2109                      IOCTL_DISK_GET_DRIVE_GEOMETRY,
2110                      NULL,
2111                      0,
2112                      &DiskGeometry,
2113                      &dwBytes );
2114 
2115         if (!NT_SUCCESS(Status)) {
2116             _SEH2_LEAVE;
2117         }
2118 
2119         Status = IoCreateDevice(
2120                      MainDeviceObject->DriverObject,
2121                      sizeof(EXT2_VCB),
2122                      NULL,
2123                      FILE_DEVICE_DISK_FILE_SYSTEM,
2124                      0,
2125                      FALSE,
2126                      &VolumeDeviceObject );
2127 
2128         if (!NT_SUCCESS(Status)) {
2129             _SEH2_LEAVE;
2130         }
2131         INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2132 
2133 #ifdef _PNP_POWER_
2134         /* don't care about power management requests */
2135         VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
2136 #endif
2137 
2138         VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
2139         ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
2140 
2141 /*
2142         These are for buffer-address alignment requirements.
2143         Never do this check, unless you want fail user requests :)
2144 
2145         if (TargetDeviceObject->AlignmentRequirement >
2146                 VolumeDeviceObject->AlignmentRequirement) {
2147 
2148             VolumeDeviceObject->AlignmentRequirement =
2149                 TargetDeviceObject->AlignmentRequirement;
2150         }
2151 
2152         if (DiskGeometry.BytesPerSector - 1 >
2153                 VolumeDeviceObject->AlignmentRequirement) {
2154             VolumeDeviceObject->AlignmentRequirement =
2155                 DiskGeometry.BytesPerSector - 1;
2156             TargetDeviceObject->AlignmentRequirement =
2157                 DiskGeometry.BytesPerSector - 1;
2158         }
2159 */
2160         (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
2161             VolumeDeviceObject;
2162         Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
2163 
2164         Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
2165 
2166         RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
2167         Vcb->Identifier.Type = EXT2VCB;
2168         Vcb->Identifier.Size = sizeof(EXT2_VCB);
2169         Vcb->TargetDeviceObject = TargetDeviceObject;
2170         Vcb->DiskGeometry = DiskGeometry;
2171         InitializeListHead(&Vcb->Next);
2172 
2173         Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
2174         if (!NT_SUCCESS(Status)) {
2175             Vcb = NULL;
2176             Status = STATUS_UNRECOGNIZED_VOLUME;
2177             _SEH2_LEAVE;
2178         }
2179         ASSERT (NULL != Ext2Sb);
2180 
2181         /* check Linux Ext2/Ext3 volume magic */
2182         if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
2183             DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
2184         } else  {
2185             Status = STATUS_UNRECOGNIZED_VOLUME;
2186             Vcb = NULL;
2187             _SEH2_LEAVE;
2188         }
2189 
2190         DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
2191 
2192         /* initialize Vcb structure */
2193         Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
2194                                     TargetDeviceObject,
2195                                     VolumeDeviceObject, Vpb);
2196 
2197         if (NT_SUCCESS(Status))  {
2198 
2199             PLIST_ENTRY List;
2200 
2201             ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
2202             GlobalDataResourceAcquired = TRUE;
2203 
2204             for (List = Ext2Global->VcbList.Flink;
2205                     List != &Ext2Global->VcbList;
2206                     List = List->Flink) {
2207 
2208                 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
2209                 OldVpb = OldVcb->Vpb;
2210 
2211                 /* in case we are already in the queue, should not happen */
2212                 if (OldVpb == Vpb) {
2213                     continue;
2214                 }
2215 
2216                 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
2217                         (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
2218                         (OldVpb->RealDevice == TargetDeviceObject) &&
2219                         (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
2220                         (RtlEqualMemory(&OldVpb->VolumeLabel[0],
2221                                         &Vpb->VolumeLabel[0],
2222                                         Vpb->VolumeLabelLength)) &&
2223                         (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
2224                                         &Vcb->SuperBlock->s_uuid[0], 16)) ) {
2225                     ClearFlag(OldVcb->Flags, VCB_MOUNTED);
2226                 }
2227             }
2228 
2229             SetLongFlag(Vcb->Flags, VCB_MOUNTED);
2230             SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
2231             Ext2InsertVcb(Vcb);
2232             Vcb = NULL;
2233             Vpb = NULL;
2234             ObDereferenceObject(TargetDeviceObject);
2235 
2236         } else {
2237 
2238             Vcb = NULL;
2239         }
2240 
2241     } _SEH2_FINALLY {
2242 
2243         if (GlobalDataResourceAcquired) {
2244             ExReleaseResourceLite(&Ext2Global->Resource);
2245         }
2246 
2247         if (!NT_SUCCESS(Status)) {
2248 
2249             if (!NT_SUCCESS(Status)) {
2250                 if ( Vpb != NULL ) {
2251                     Vpb->DeviceObject = NULL;
2252                 }
2253             }
2254 
2255             if (Vcb) {
2256                 Ext2DestroyVcb(Vcb);
2257             } else {
2258                 if (Ext2Sb) {
2259                     Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
2260                 }
2261                 if (VolumeDeviceObject) {
2262                     IoDeleteDevice(VolumeDeviceObject);
2263                     DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2264                 }
2265             }
2266         }
2267 
2268         if (!IrpContext->ExceptionInProgress) {
2269             Ext2CompleteIrpContext(IrpContext,  Status);
2270         }
2271     } _SEH2_END;
2272 
2273     return Status;
2274 }
2275 
2276 VOID
2277 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
2278                IN PEXT2_VCB         Vcb )
2279 {
2280     NTSTATUS                Status = STATUS_SUCCESS;
2281 
2282     BOOLEAN                 bVerify = FALSE;
2283     ULONG                   ChangeCount = 0;
2284     ULONG                   dwBytes;
2285 
2286     PIRP                    Irp;
2287     PEXTENDED_IO_STACK_LOCATION      IrpSp;
2288 
2289     _SEH2_TRY {
2290 
2291         ASSERT(IrpContext != NULL);
2292 
2293         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2294                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2295 
2296         Irp = IrpContext->Irp;
2297         IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
2298 
2299         bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2300 
2301         if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
2302                 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
2303 
2304             dwBytes = sizeof(ULONG);
2305             Status = Ext2DiskIoControl(
2306                          Vcb->TargetDeviceObject,
2307                          IOCTL_DISK_CHECK_VERIFY,
2308                          NULL,
2309                          0,
2310                          &ChangeCount,
2311                          &dwBytes );
2312 
2313             if ( STATUS_VERIFY_REQUIRED == Status ||
2314                     STATUS_DEVICE_NOT_READY == Status ||
2315                     STATUS_NO_MEDIA_IN_DEVICE == Status ||
2316                     (NT_SUCCESS(Status) &&
2317                      (ChangeCount != Vcb->ChangeCount))) {
2318 
2319                 KIRQL Irql;
2320 
2321                 IoAcquireVpbSpinLock(&Irql);
2322                 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2323                     SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2324                 }
2325                 IoReleaseVpbSpinLock(Irql);
2326 
2327             } else {
2328 
2329                 if (!NT_SUCCESS(Status)) {
2330                     Ext2NormalizeAndRaiseStatus(IrpContext, Status);
2331                 }
2332             }
2333         }
2334 
2335         if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
2336             IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2337             Ext2NormalizeAndRaiseStatus ( IrpContext,
2338                                           STATUS_VERIFY_REQUIRED );
2339         }
2340 
2341         if (IsMounted(Vcb)) {
2342 
2343             if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
2344                     (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
2345                     (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
2346                     (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
2347                     (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
2348                     (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2349                      IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2350                      IrpSp->Parameters.FileSystemControl.FsControlCode ==
2351                      FSCTL_MARK_VOLUME_DIRTY)) {
2352 
2353                 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
2354 
2355                     KIRQL Irql;
2356 
2357                     IoAcquireVpbSpinLock(&Irql);
2358                     if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2359                         SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2360                     }
2361                     IoReleaseVpbSpinLock(Irql);
2362 
2363                     IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2364 
2365                     Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
2366                 }
2367             }
2368         }
2369 
2370     } _SEH2_FINALLY {
2371 
2372     } _SEH2_END;
2373 
2374 }
2375 
2376 
2377 NTSTATUS
2378 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2379 {
2380     PDEVICE_OBJECT          DeviceObject;
2381     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
2382     PEXT2_SUPER_BLOCK       ext2_sb = NULL;
2383     PEXT2_VCB               Vcb = NULL;
2384     BOOLEAN                 VcbResourceAcquired = FALSE;
2385     PIRP                    Irp;
2386     ULONG                   ChangeCount = 0;
2387     ULONG                   dwBytes;
2388 
2389     _SEH2_TRY {
2390 
2391         ASSERT(IrpContext != NULL);
2392         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2393                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2394 
2395         DeviceObject = IrpContext->DeviceObject;
2396         //
2397         // This request is not allowed on the main device object
2398         //
2399         if (IsExt2FsDevice(DeviceObject)) {
2400             Status = STATUS_INVALID_DEVICE_REQUEST;
2401             _SEH2_LEAVE;
2402         }
2403 
2404         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2405         ASSERT(Vcb != NULL);
2406         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2407                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2408 
2409         VcbResourceAcquired =
2410             ExAcquireResourceExclusiveLite(
2411                 &Vcb->MainResource,
2412                 TRUE );
2413 
2414         if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
2415             Status = STATUS_SUCCESS;
2416             _SEH2_LEAVE;
2417         }
2418 
2419         if (!IsMounted(Vcb)) {
2420             Status = STATUS_WRONG_VOLUME;
2421             _SEH2_LEAVE;
2422         }
2423 
2424         dwBytes = sizeof(ULONG);
2425         Status = Ext2DiskIoControl(
2426                      Vcb->TargetDeviceObject,
2427                      IOCTL_DISK_CHECK_VERIFY,
2428                      NULL,
2429                      0,
2430                      &ChangeCount,
2431                      &dwBytes );
2432 
2433 
2434         if (!NT_SUCCESS(Status)) {
2435             Status = STATUS_WRONG_VOLUME;
2436             _SEH2_LEAVE;
2437         } else {
2438             Vcb->ChangeCount = ChangeCount;
2439         }
2440 
2441         Irp = IrpContext->Irp;
2442 
2443         Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
2444 
2445         if (!NT_SUCCESS(Status)) {
2446             _SEH2_LEAVE;
2447         }
2448 
2449         ASSERT(NULL != ext2_sb);
2450         if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
2451                 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
2452                 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
2453 
2454             ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2455 
2456             if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
2457                 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2458             } else {
2459                 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2460             }
2461 
2462             DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
2463 
2464         } else {
2465 
2466             Status = STATUS_WRONG_VOLUME;
2467             Ext2PurgeVolume(Vcb, FALSE);
2468 
2469             SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2470             ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2471 
2472             DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
2473         }
2474 
2475     } _SEH2_FINALLY {
2476 
2477         if (ext2_sb)
2478             Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
2479 
2480         if (VcbResourceAcquired) {
2481             ExReleaseResourceLite(&Vcb->MainResource);
2482         }
2483 
2484         if (!IrpContext->ExceptionInProgress) {
2485             Ext2CompleteIrpContext(IrpContext,  Status);
2486         }
2487     } _SEH2_END;
2488 
2489     return Status;
2490 }
2491 
2492 
2493 NTSTATUS
2494 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
2495 {
2496     PDEVICE_OBJECT      DeviceObject;
2497     PEXT2_VCB           Vcb = 0;
2498     NTSTATUS            Status = STATUS_SUCCESS;
2499 
2500     ASSERT(IrpContext);
2501 
2502     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2503            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2504 
2505 
2506     DeviceObject = IrpContext->DeviceObject;
2507 
2508     Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2509 
2510     ASSERT(IsMounted(Vcb));
2511 
2512     Ext2VerifyVcb (IrpContext, Vcb);
2513 
2514     Ext2CompleteIrpContext(IrpContext,  Status);
2515 
2516     return Status;
2517 }
2518 
2519 
2520 NTSTATUS
2521 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2522 {
2523     PDEVICE_OBJECT  DeviceObject;
2524     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
2525     PEXT2_VCB       Vcb = NULL;
2526     BOOLEAN         VcbResourceAcquired = FALSE;
2527 
2528     _SEH2_TRY {
2529 
2530         ASSERT(IrpContext != NULL);
2531 
2532         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2533                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2534 
2535         DeviceObject = IrpContext->DeviceObject;
2536 
2537         //
2538         // This request is not allowed on the main device object
2539         //
2540         if (IsExt2FsDevice(DeviceObject)) {
2541             Status = STATUS_INVALID_DEVICE_REQUEST;
2542             _SEH2_LEAVE;
2543         }
2544 
2545         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2546 
2547         ASSERT(Vcb != NULL);
2548 
2549         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2550                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2551 
2552         ASSERT(IsMounted(Vcb));
2553 
2554         ExAcquireResourceExclusiveLite(
2555             &Vcb->MainResource,
2556             TRUE );
2557 
2558         VcbResourceAcquired = TRUE;
2559 
2560         if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2561             Status = STATUS_VOLUME_DISMOUNTED;
2562             _SEH2_LEAVE;
2563         }
2564 
2565         Ext2FlushFiles(IrpContext, Vcb, FALSE);
2566         Ext2FlushVolume(IrpContext, Vcb, FALSE);
2567 
2568         ExReleaseResourceLite(&Vcb->MainResource);
2569         VcbResourceAcquired = FALSE;
2570 
2571         Ext2PurgeVolume(Vcb, TRUE);
2572         Ext2CheckDismount(IrpContext, Vcb, TRUE);
2573 
2574         DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
2575         Status = STATUS_SUCCESS;
2576 
2577     } _SEH2_FINALLY {
2578 
2579         if (VcbResourceAcquired) {
2580             ExReleaseResourceLite(&Vcb->MainResource);
2581         }
2582 
2583         if (!IrpContext->ExceptionInProgress) {
2584             Ext2CompleteIrpContext(IrpContext,  Status);
2585         }
2586     } _SEH2_END;
2587 
2588     return Status;
2589 }
2590 
2591 BOOLEAN
2592 Ext2CheckDismount (
2593     IN PEXT2_IRP_CONTEXT IrpContext,
2594     IN PEXT2_VCB         Vcb,
2595     IN BOOLEAN           bForce   )
2596 {
2597     KIRQL   Irql;
2598     PVPB    Vpb = Vcb->Vpb, NewVpb = NULL;
2599     BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
2600     ULONG   UnCleanCount = 0;
2601 
2602     NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
2603     if (NewVpb == NULL) {
2604         DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
2605         return FALSE;
2606     }
2607     DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
2608     INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2609     memset(NewVpb, '_', VPB_SIZE);
2610     RtlZeroMemory(NewVpb, sizeof(VPB));
2611 
2612     ExAcquireResourceExclusiveLite(
2613         &Ext2Global->Resource, TRUE );
2614 
2615     ExAcquireResourceExclusiveLite(
2616         &Vcb->MainResource, TRUE );
2617 
2618     if (IrpContext &&
2619         IrpContext->MajorFunction == IRP_MJ_CREATE &&
2620         IrpContext->RealDevice == Vcb->RealDevice) {
2621         UnCleanCount = 2;
2622     } else {
2623         UnCleanCount = 1;
2624     }
2625 
2626     IoAcquireVpbSpinLock (&Irql);
2627 
2628     DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
2629                    Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
2630 
2631     if (Vpb->ReferenceCount <= UnCleanCount) {
2632 
2633         if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2634 
2635             ClearFlag(Vpb->Flags, VPB_MOUNTED);
2636             ClearFlag(Vpb->Flags, VPB_LOCKED);
2637 
2638             if ((Vcb->RealDevice != Vpb->RealDevice) &&
2639                     (Vcb->RealDevice->Vpb == Vpb)) {
2640                 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
2641                 SetFlag(Vpb->Flags, VPB_PERSISTENT );
2642             }
2643 
2644             Ext2RemoveVcb(Vcb);
2645             SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2646         }
2647 
2648         if (Vpb->ReferenceCount) {
2649             bTearDown = TRUE;
2650         } else {
2651             bDeleted = TRUE;
2652             Vpb->DeviceObject = NULL;
2653         }
2654 
2655         DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
2656                         Vpb, bDeleted, bTearDown));
2657 
2658 
2659     } else if (bForce) {
2660 
2661         DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
2662                         NewVpb, Vcb->Vpb, Vpb->RealDevice));
2663 
2664         /* keep vpb president and later we'll free it */
2665         SetFlag(Vpb->Flags, VPB_PERSISTENT);
2666 
2667         Vcb->Vpb2 = Vcb->Vpb;
2668         NewVpb->Type = IO_TYPE_VPB;
2669         NewVpb->Size = sizeof(VPB);
2670         NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
2671         NewVpb->RealDevice = Vpb->RealDevice;
2672         NewVpb->RealDevice->Vpb = NewVpb;
2673         NewVpb = NULL;
2674         ClearFlag(Vpb->Flags, VPB_MOUNTED);
2675         SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
2676         ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
2677     }
2678 
2679     IoReleaseVpbSpinLock(Irql);
2680 
2681     ExReleaseResourceLite(&Vcb->MainResource);
2682     ExReleaseResourceLite(&Ext2Global->Resource);
2683 
2684     if (bTearDown) {
2685         DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
2686         Ext2TearDownStream(Vcb);
2687     }
2688 
2689     if (bDeleted) {
2690         DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
2691         Ext2DestroyVcb(Vcb);
2692     }
2693 
2694     if (NewVpb != NULL) {
2695         DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
2696         ExFreePoolWithTag(NewVpb, TAG_VPB);
2697         DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2698     }
2699 
2700     return bDeleted;
2701 }
2702 
2703 NTSTATUS
2704 Ext2PurgeVolume (IN PEXT2_VCB Vcb,
2705                  IN BOOLEAN  FlushBeforePurge )
2706 {
2707     PEXT2_FCB       Fcb;
2708     LIST_ENTRY      List, *Next;
2709 
2710     BOOLEAN         VcbResourceAcquired = FALSE;
2711     BOOLEAN         FcbResourceAcquired = FALSE;
2712     BOOLEAN         gdResourceAcquired = FALSE;
2713 
2714     _SEH2_TRY {
2715 
2716         ASSERT(Vcb != NULL);
2717         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2718                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2719 
2720         ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2721         VcbResourceAcquired = TRUE;
2722 
2723         if (IsVcbReadOnly(Vcb)) {
2724             FlushBeforePurge = FALSE;
2725         }
2726 
2727         InitializeListHead(&List);
2728 
2729         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
2730         FcbResourceAcquired = TRUE;
2731 
2732         while (!IsListEmpty(&Vcb->FcbList)) {
2733 
2734             Next = RemoveHeadList(&Vcb->FcbList);
2735             Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
2736 
2737             DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n",
2738                             &Fcb->Mcb->FullName, Fcb->ReferenceCount));
2739             InsertTailList(&List, &Fcb->Next);
2740         }
2741 
2742         while (!IsListEmpty(&List)) {
2743 
2744             Next = RemoveHeadList(&List);
2745             Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
2746 
2747             if (ExAcquireResourceExclusiveLite(
2748                         &Fcb->MainResource,
2749                         TRUE )) {
2750 
2751                 Ext2PurgeFile(Fcb, FlushBeforePurge);
2752 
2753                 if (Fcb->ReferenceCount <= 1) {
2754                     Fcb->TsDrop.QuadPart = 0;
2755                     InsertHeadList(&Vcb->FcbList, &Fcb->Next);
2756                 } else {
2757                     InsertTailList(&Vcb->FcbList, &Fcb->Next);
2758                 }
2759                 ExReleaseResourceLite(&Fcb->MainResource);
2760             }
2761         }
2762 
2763         if (FcbResourceAcquired) {
2764             ExReleaseResourceLite(&Vcb->FcbLock);
2765             FcbResourceAcquired = FALSE;
2766         }
2767 
2768         /* acquire bd lock to avoid bh creation */
2769         ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
2770         gdResourceAcquired = TRUE;
2771 
2772         /* discard buffer_headers for group_desc */
2773         Ext2DropBH(Vcb);
2774 
2775         if (FlushBeforePurge) {
2776             ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
2777             ExReleaseResourceLite(&Vcb->PagingIoResource);
2778 
2779             CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
2780         }
2781 
2782         if (Vcb->SectionObject.ImageSectionObject) {
2783             MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
2784         }
2785 
2786         if (Vcb->SectionObject.DataSectionObject) {
2787             CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
2788         }
2789 
2790         DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
2791 
2792     } _SEH2_FINALLY {
2793 
2794         if (gdResourceAcquired) {
2795             ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
2796         }
2797 
2798         if (FcbResourceAcquired) {
2799             ExReleaseResourceLite(&Vcb->FcbLock);
2800         }
2801 
2802         if (VcbResourceAcquired) {
2803             ExReleaseResourceLite(&Vcb->MainResource);
2804         }
2805     } _SEH2_END;
2806 
2807     return STATUS_SUCCESS;
2808 }
2809 
2810 NTSTATUS
2811 Ext2PurgeFile ( IN PEXT2_FCB Fcb,
2812                 IN BOOLEAN  FlushBeforePurge )
2813 {
2814     IO_STATUS_BLOCK    IoStatus;
2815 
2816     ASSERT(Fcb != NULL);
2817 
2818     ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
2819            (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
2820 
2821 
2822     if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
2823         DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
2824                         &Fcb->Mcb->FullName));
2825         ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
2826         ExReleaseResourceLite(&Fcb->PagingIoResource);
2827         CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
2828         ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
2829     }
2830 
2831     if (Fcb->SectionObject.ImageSectionObject) {
2832         DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
2833                         &Fcb->Mcb->FullName));
2834         MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
2835     }
2836 
2837     if (Fcb->SectionObject.DataSectionObject) {
2838         DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
2839                         &Fcb->Mcb->FullName));
2840         CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
2841     }
2842 
2843     return STATUS_SUCCESS;
2844 }
2845 
2846 
2847 NTSTATUS
2848 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
2849 {
2850     NTSTATUS    Status;
2851 
2852     ASSERT(IrpContext);
2853 
2854     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2855            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2856 
2857     switch (IrpContext->MinorFunction) {
2858 
2859     case IRP_MN_USER_FS_REQUEST:
2860         Status = Ext2UserFsRequest(IrpContext);
2861         break;
2862 
2863     case IRP_MN_MOUNT_VOLUME:
2864         Status = Ext2MountVolume(IrpContext);
2865         break;
2866 
2867     case IRP_MN_VERIFY_VOLUME:
2868         Status = Ext2VerifyVolume(IrpContext);
2869         break;
2870 
2871     default:
2872 
2873         DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
2874         Status = STATUS_INVALID_DEVICE_REQUEST;
2875         Ext2CompleteIrpContext(IrpContext,  Status);
2876     }
2877 
2878     return Status;
2879 }
2880