xref: /reactos/drivers/filesystems/ext2/src/devctl.c (revision aaeb131b)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             devctl.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 __REACTOS__
21 NTSTATUS NTAPI
22 #else
23 NTSTATUS
24 #endif
25 Ext2DeviceControlCompletion (
26     IN PDEVICE_OBJECT   DeviceObject,
27     IN PIRP             Irp,
28     IN PVOID            Context);
29 
30 
31 #ifdef ALLOC_PRAGMA
32 #pragma alloc_text(PAGE, Ext2DeviceControl)
33 #pragma alloc_text(PAGE, Ext2DeviceControlNormal)
34 #pragma alloc_text(PAGE, Ext2ProcessVolumeProperty)
35 #pragma alloc_text(PAGE, Ext2ProcessUserProperty)
36 #pragma alloc_text(PAGE, Ext2ProcessGlobalProperty)
37 #pragma alloc_text(PAGE, Ex2ProcessUserPerfStat)
38 #pragma alloc_text(PAGE, Ex2ProcessMountPoint)
39 #if EXT2_UNLOAD
40 #pragma alloc_text(PAGE, Ext2PrepareToUnload)
41 #endif
42 #endif
43 
44 
45 #ifdef __REACTOS__
46 NTSTATUS NTAPI
47 #else
48 NTSTATUS
49 #endif
Ext2DeviceControlCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)50 Ext2DeviceControlCompletion (
51     IN PDEVICE_OBJECT   DeviceObject,
52     IN PIRP             Irp,
53     IN PVOID            Context
54 )
55 {
56     if (Irp->PendingReturned) {
57         IoMarkIrpPending(Irp);
58     }
59 
60     return STATUS_SUCCESS;
61 }
62 
63 
64 NTSTATUS
Ext2DeviceControlNormal(IN PEXT2_IRP_CONTEXT IrpContext)65 Ext2DeviceControlNormal (IN PEXT2_IRP_CONTEXT IrpContext)
66 {
67     PDEVICE_OBJECT  DeviceObject;
68     BOOLEAN         CompleteRequest = TRUE;
69     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
70 
71     PEXT2_VCB       Vcb;
72 
73     PIRP            Irp;
74     PIO_STACK_LOCATION IrpSp;
75     PIO_STACK_LOCATION NextIrpSp;
76 
77     PDEVICE_OBJECT  TargetDeviceObject;
78 
79     _SEH2_TRY {
80 
81         ASSERT(IrpContext != NULL);
82 
83         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
84                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
85 
86         CompleteRequest = TRUE;
87 
88         DeviceObject = IrpContext->DeviceObject;
89 
90         if (IsExt2FsDevice(DeviceObject))  {
91             Status = STATUS_INVALID_DEVICE_REQUEST;
92             _SEH2_LEAVE;
93         }
94 
95         Irp = IrpContext->Irp;
96         IrpSp = IoGetCurrentIrpStackLocation(Irp);
97 
98         Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
99 
100         if (!((Vcb) && (Vcb->Identifier.Type == EXT2VCB) &&
101                 (Vcb->Identifier.Size == sizeof(EXT2_VCB)))) {
102             Status = STATUS_INVALID_PARAMETER;
103             _SEH2_LEAVE;
104         }
105 
106         TargetDeviceObject = Vcb->TargetDeviceObject;
107 
108         //
109         // Pass on the IOCTL to the driver below
110         //
111 
112         CompleteRequest = FALSE;
113 
114         NextIrpSp = IoGetNextIrpStackLocation( Irp );
115         *NextIrpSp = *IrpSp;
116 
117         IoSetCompletionRoutine(
118             Irp,
119             Ext2DeviceControlCompletion,
120             NULL,
121             FALSE,
122             TRUE,
123             TRUE );
124 
125         Status = IoCallDriver(TargetDeviceObject, Irp);
126 
127     } _SEH2_FINALLY  {
128 
129         if (!IrpContext->ExceptionInProgress) {
130             if (IrpContext) {
131                 if (!CompleteRequest) {
132                     IrpContext->Irp = NULL;
133                 }
134 
135                 Ext2CompleteIrpContext(IrpContext, Status);
136             }
137         }
138     } _SEH2_END;
139 
140     return Status;
141 }
142 
143 
144 #if EXT2_UNLOAD
145 
146 NTSTATUS
Ext2PrepareToUnload(IN PEXT2_IRP_CONTEXT IrpContext)147 Ext2PrepareToUnload (IN PEXT2_IRP_CONTEXT IrpContext)
148 {
149     PDEVICE_OBJECT  DeviceObject;
150     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
151     BOOLEAN         GlobalDataResourceAcquired = FALSE;
152 
153     _SEH2_TRY {
154 
155         ASSERT(IrpContext != NULL);
156 
157         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
158                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
159 
160         DeviceObject = IrpContext->DeviceObject;
161 
162         if (IsExt2FsDevice(DeviceObject)) {
163             Status = STATUS_INVALID_DEVICE_REQUEST;
164             _SEH2_LEAVE;
165         }
166 
167         ExAcquireResourceExclusiveLite(
168             &Ext2Global->Resource,
169             TRUE );
170 
171         GlobalDataResourceAcquired = TRUE;
172 
173         if (FlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
174             DEBUG(DL_ERR, ( "Ext2PrepareUnload:  Already ready to unload.\n"));
175 
176             Status = STATUS_ACCESS_DENIED;
177 
178             _SEH2_LEAVE;
179         }
180 
181         {
182             PEXT2_VCB               Vcb;
183             PLIST_ENTRY             ListEntry;
184 
185             ListEntry = Ext2Global->VcbList.Flink;
186 
187             while (ListEntry != &(Ext2Global->VcbList)) {
188 
189                 Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
190                 ListEntry = ListEntry->Flink;
191 
192                 if (Vcb && (!Vcb->ReferenceCount) &&
193                         IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
194                     Ext2RemoveVcb(Vcb);
195                     Ext2ClearVpbFlag(Vcb->Vpb, VPB_MOUNTED);
196 
197                     Ext2DestroyVcb(Vcb);
198                 }
199             }
200         }
201 
202         if (!IsListEmpty(&(Ext2Global->VcbList))) {
203 
204             DEBUG(DL_ERR, ( "Ext2PrepareUnload:  Mounted volumes exists.\n"));
205 
206             Status = STATUS_ACCESS_DENIED;
207 
208             _SEH2_LEAVE;
209         }
210 
211         IoUnregisterFileSystem(Ext2Global->DiskdevObject);
212         IoUnregisterFileSystem(Ext2Global->CdromdevObject);
213         Ext2Global->DriverObject->DriverUnload = DriverUnload;
214         SetLongFlag(Ext2Global->Flags ,EXT2_UNLOAD_PENDING);
215         Status = STATUS_SUCCESS;
216 
217         DEBUG(DL_INF, ( "Ext2PrepareToUnload: Driver is ready to unload.\n"));
218 
219     } _SEH2_FINALLY {
220 
221         if (GlobalDataResourceAcquired) {
222             ExReleaseResourceLite(&Ext2Global->Resource);
223         }
224 
225         if (!IrpContext->ExceptionInProgress) {
226             Ext2CompleteIrpContext(IrpContext, Status);
227         }
228     } _SEH2_END;
229 
230     return Status;
231 }
232 
233 #endif
234 
235 extern CHAR gVersion[];
236 extern CHAR gTime[];
237 extern CHAR gDate[];
238 
239 NTSTATUS
Ext2ProcessGlobalProperty(IN PDEVICE_OBJECT DeviceObject,IN PEXT2_VOLUME_PROPERTY3 Property3,IN ULONG Length)240 Ext2ProcessGlobalProperty(
241     IN  PDEVICE_OBJECT  DeviceObject,
242     IN  PEXT2_VOLUME_PROPERTY3 Property3,
243     IN  ULONG Length
244 )
245 {
246     PEXT2_VOLUME_PROPERTY3 Property2 = (PVOID)Property3;
247     PEXT2_VOLUME_PROPERTY  Property = (PVOID)Property3;
248     struct nls_table * PageTable = NULL;
249 
250     NTSTATUS        Status = STATUS_SUCCESS;
251     BOOLEAN         GlobalDataResourceAcquired = FALSE;
252 
253     _SEH2_TRY {
254 
255         if (Length < 8 || !IsFlagOn(Property->Flags, EXT2_FLAG_VP_SET_GLOBAL)) {
256             Status = STATUS_INVALID_PARAMETER;
257             _SEH2_LEAVE;
258         }
259 
260         /* query Ext2Fsd's version and built date/time*/
261         if (Property->Command == APP_CMD_QUERY_VERSION) {
262             PEXT2_VOLUME_PROPERTY_VERSION PVPV =
263                 (PEXT2_VOLUME_PROPERTY_VERSION) Property;
264 
265             if (Length < sizeof(EXT2_VOLUME_PROPERTY_VERSION)) {
266                 Status = STATUS_INVALID_PARAMETER;
267                 _SEH2_LEAVE;
268             }
269 
270             RtlZeroMemory(&PVPV->Date[0],   0x20);
271             RtlZeroMemory(&PVPV->Time[0],   0x20);
272             RtlZeroMemory(&PVPV->Version[0],0x1C);
273             strncpy(&PVPV->Version[0], gVersion, 0x1B);
274             strncpy(&PVPV->Date[0], gDate, 0x1F);
275             strncpy(&PVPV->Time[0], gTime, 0x1F);
276             _SEH2_LEAVE;
277         }
278 
279         /* must be property query/set commands */
280         if (Property->Command == APP_CMD_SET_PROPERTY) {
281             if (Length < sizeof(EXT2_VOLUME_PROPERTY)) {
282                 Status = STATUS_INVALID_PARAMETER;
283                 _SEH2_LEAVE;
284             }
285         } else if (Property->Command == APP_CMD_SET_PROPERTY2) {
286             if (Length < sizeof(EXT2_VOLUME_PROPERTY2)) {
287                 Status = STATUS_INVALID_PARAMETER;
288                 _SEH2_LEAVE;
289             }
290         } else if (Property->Command == APP_CMD_SET_PROPERTY3) {
291             if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) {
292                 Status = STATUS_INVALID_PARAMETER;
293                 _SEH2_LEAVE;
294             }
295         } else {
296             Status = STATUS_INVALID_PARAMETER;
297             _SEH2_LEAVE;
298         }
299 
300         ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
301         GlobalDataResourceAcquired = TRUE;
302 
303 
304         switch (Property->Command) {
305 
306             case APP_CMD_SET_PROPERTY3:
307 
308             if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) {
309                 if (Property3->AutoMount)
310                     SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
311                 else
312                     ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
313             }
314 
315             case APP_CMD_SET_PROPERTY2:
316 
317             RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN);
318             if ((Ext2Global->bHidingPrefix = Property2->bHidingPrefix)) {
319                 RtlCopyMemory( Ext2Global->sHidingPrefix,
320                                Property2->sHidingPrefix,
321                                HIDINGPAT_LEN - 1);
322             }
323             RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN);
324             if ((Ext2Global->bHidingSuffix = Property2->bHidingSuffix)) {
325                 RtlCopyMemory( Ext2Global->sHidingSuffix,
326                                Property2->sHidingSuffix,
327                                HIDINGPAT_LEN - 1);
328             }
329 
330             case APP_CMD_SET_PROPERTY:
331 
332             if (Property->bReadonly) {
333                 ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
334                 ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
335             } else {
336                 SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
337                 if (Property->bExt3Writable) {
338                     SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
339                 } else {
340                     ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
341                 }
342             }
343 
344             PageTable = load_nls(Property->Codepage);
345             if (PageTable) {
346                 memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
347                 Ext2Global->Codepage.PageTable = PageTable;
348             }
349 
350             break;
351 
352             default:
353             break;
354         }
355 
356     } _SEH2_FINALLY {
357 
358         if (GlobalDataResourceAcquired) {
359             ExReleaseResourceLite(&Ext2Global->Resource);
360         }
361     } _SEH2_END;
362 
363     return Status;
364 }
365 
366 
367 NTSTATUS
Ext2ProcessVolumeProperty(IN PEXT2_VCB Vcb,IN PEXT2_VOLUME_PROPERTY3 Property3,IN ULONG Length)368 Ext2ProcessVolumeProperty(
369     IN  PEXT2_VCB              Vcb,
370     IN  PEXT2_VOLUME_PROPERTY3 Property3,
371     IN  ULONG Length
372 )
373 {
374     struct nls_table * PageTable = NULL;
375     PEXT2_VOLUME_PROPERTY2 Property2 = (PVOID)Property3;
376     PEXT2_VOLUME_PROPERTY  Property = (PVOID)Property3;
377     NTSTATUS Status = STATUS_SUCCESS;
378     BOOLEAN VcbResourceAcquired = FALSE;
379 
380     _SEH2_TRY {
381 
382         ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
383         VcbResourceAcquired = TRUE;
384 
385         if (Property->Command == APP_CMD_SET_PROPERTY ||
386             Property->Command == APP_CMD_QUERY_PROPERTY) {
387             if (Length < sizeof(EXT2_VOLUME_PROPERTY)) {
388                 Status = STATUS_INVALID_PARAMETER;
389                 _SEH2_LEAVE;
390             }
391         } else if (Property->Command == APP_CMD_SET_PROPERTY2 ||
392                    Property->Command == APP_CMD_QUERY_PROPERTY2) {
393             if (Length < sizeof(EXT2_VOLUME_PROPERTY2)) {
394                 Status = STATUS_INVALID_PARAMETER;
395                 _SEH2_LEAVE;
396             }
397         } else if (Property->Command == APP_CMD_SET_PROPERTY3 ||
398                    Property->Command == APP_CMD_QUERY_PROPERTY3) {
399             if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) {
400                 Status = STATUS_INVALID_PARAMETER;
401                 _SEH2_LEAVE;
402             }
403         }
404 
405         switch (Property->Command) {
406 
407         case APP_CMD_SET_PROPERTY3:
408 
409             if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) {
410                 if (Property3->AutoMount)
411                     SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
412                 else
413                     ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
414             }
415             if (Property3->Flags2 & EXT2_VPROP3_USERIDS) {
416                 SetFlag(Vcb->Flags, VCB_USER_IDS);
417                 Vcb->uid = Property3->uid;
418                 Vcb->gid = Property3->gid;
419                 if (Property3->EIDS) {
420                     Vcb->euid = Property3->euid;
421                     Vcb->egid = Property3->egid;
422                     SetFlag(Vcb->Flags, VCB_USER_EIDS);
423                 } else {
424                     Vcb->euid = Vcb->egid = 0;
425                     ClearFlag(Vcb->Flags, VCB_USER_EIDS);
426                 }
427             } else {
428                 ClearFlag(Vcb->Flags, VCB_USER_IDS);
429                 ClearFlag(Vcb->Flags, VCB_USER_EIDS);
430                 Vcb->uid = Vcb->gid = 0;
431                 Vcb->euid = Vcb->egid = 0;
432             }
433 
434         case APP_CMD_SET_PROPERTY2:
435 
436             RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN);
437 #ifdef __REACTOS__
438             if (Vcb->bHidingPrefix == Property2->bHidingPrefix) {
439 #else
440             if (Vcb->bHidingPrefix = Property2->bHidingPrefix) {
441 #endif
442                 RtlCopyMemory( Vcb->sHidingPrefix,
443                                Property2->sHidingPrefix,
444                                HIDINGPAT_LEN - 1);
445             }
446 
447             RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
448 #ifdef __REACTOS__
449             if (Vcb->bHidingSuffix == Property2->bHidingSuffix) {
450 #else
451             if (Vcb->bHidingSuffix = Property2->bHidingSuffix) {
452 #endif
453                 RtlCopyMemory( Vcb->sHidingSuffix,
454                                Property2->sHidingSuffix,
455                                HIDINGPAT_LEN - 1);
456             }
457             Vcb->DrvLetter = Property2->DrvLetter;
458 
459         case APP_CMD_SET_PROPERTY:
460 
461             if (Property->bReadonly) {
462                 if (IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) {
463                     Ext2FlushFiles(NULL, Vcb, FALSE);
464                     Ext2FlushVolume(NULL, Vcb, FALSE);
465                 }
466                 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
467 
468             } else {
469 
470                 if (Property->bExt3Writable) {
471                     SetLongFlag(Vcb->Flags, VCB_FORCE_WRITING);
472                 }
473 
474                 if (!Vcb->IsExt3fs) {
475                     ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
476                 } else if (!Property->bExt3Writable) {
477                     SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
478                 } else if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
479                     ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
480                     Ext2RecoverJournal(NULL, Vcb);
481                     if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
482                         SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
483                     } else {
484                         ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
485                     }
486                 } else {
487                     ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
488                 }
489             }
490 
491             PageTable = load_nls(Property->Codepage);
492             memcpy(Vcb->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
493             Vcb->Codepage.PageTable = PageTable;
494             if (Vcb->Codepage.PageTable) {
495                 Ext2InitializeLabel(Vcb, Vcb->SuperBlock);
496             }
497 
498             break;
499 
500         case APP_CMD_QUERY_PROPERTY3:
501 
502             if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
503                 SetFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT);
504                 Property3->AutoMount = TRUE;
505             } else {
506                 ClearFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT);
507                 Property3->AutoMount = FALSE;
508             }
509 
510             if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) {
511                 SetFlag(Property3->Flags2, EXT2_VPROP3_USERIDS);
512                 Property3->uid = Vcb->uid;
513                 Property3->gid = Vcb->gid;
514                 if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
515                     Property3->EIDS = TRUE;
516                     Property3->euid = Vcb->euid;
517                     Property3->egid = Vcb->egid;
518                 } else {
519                     Property3->EIDS = FALSE;
520                 }
521             } else {
522                 ClearFlag(Property3->Flags2, EXT2_VPROP3_USERIDS);
523             }
524 
525         case APP_CMD_QUERY_PROPERTY2:
526 
527             RtlCopyMemory(Property2->UUID, Vcb->SuperBlock->s_uuid, 16);
528             Property2->DrvLetter = Vcb->DrvLetter;
529 
530 #ifdef __REACTOS__
531             if (Property2->bHidingPrefix == Vcb->bHidingPrefix) {
532 #else
533             if (Property2->bHidingPrefix = Vcb->bHidingPrefix) {
534 #endif
535                 RtlCopyMemory( Property2->sHidingPrefix,
536                                Vcb->sHidingPrefix,
537                                HIDINGPAT_LEN);
538             } else {
539                 RtlZeroMemory( Property2->sHidingPrefix,
540                                HIDINGPAT_LEN);
541             }
542 
543 #ifdef __REACTOS__
544             if (Property2->bHidingSuffix == Vcb->bHidingSuffix) {
545 #else
546             if (Property2->bHidingSuffix = Vcb->bHidingSuffix) {
547 #endif
548                 RtlCopyMemory( Property2->sHidingSuffix,
549                                Vcb->sHidingSuffix,
550                                HIDINGPAT_LEN);
551             } else {
552                 RtlZeroMemory( Property2->sHidingSuffix,
553                                HIDINGPAT_LEN);
554             }
555 
556         case APP_CMD_QUERY_PROPERTY:
557 
558             Property->bExt2 = TRUE;
559             Property->bExt3 = Vcb->IsExt3fs;
560             Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY);
561             if (!Property->bReadonly && Vcb->IsExt3fs) {
562                 Property->bExt3Writable = TRUE;
563             } else {
564                 Property->bExt3Writable = FALSE;
565             }
566 
567             RtlZeroMemory(Property->Codepage, CODEPAGE_MAXLEN);
568             if (Vcb->Codepage.PageTable) {
569                 strncpy(Property->Codepage, Vcb->Codepage.PageTable->charset, CODEPAGE_MAXLEN);
570             } else {
571                 strncpy(Property->Codepage, "default", CODEPAGE_MAXLEN);
572             }
573             break;
574 
575         default:
576             Status = STATUS_INVALID_PARAMETER;
577             break;
578         }
579 
580     } _SEH2_FINALLY {
581 
582         if (VcbResourceAcquired) {
583             ExReleaseResourceLite(&Vcb->MainResource);
584         }
585     } _SEH2_END;
586 
587     return Status;
588 }
589 
590 NTSTATUS
591 Ext2ProcessUserProperty(
592     IN PEXT2_IRP_CONTEXT        IrpContext,
593     IN PEXT2_VOLUME_PROPERTY3   Property,
594     IN ULONG                    Length
595 )
596 {
597     NTSTATUS    Status = STATUS_SUCCESS;
598     PEXT2_VCB   Vcb = NULL;
599     PDEVICE_OBJECT  DeviceObject = NULL;
600 
601     _SEH2_TRY {
602 
603         ASSERT(IrpContext != NULL);
604         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
605                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
606 
607         if (Property->Magic != EXT2_VOLUME_PROPERTY_MAGIC) {
608             Status = STATUS_INVALID_PARAMETER;
609             _SEH2_LEAVE;
610         }
611 
612         DeviceObject = IrpContext->DeviceObject;
613         if (IsExt2FsDevice(DeviceObject)) {
614             Status = Ext2ProcessGlobalProperty(DeviceObject, Property, Length);
615         } else {
616             Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
617             if (!((Vcb) && (Vcb->Identifier.Type == EXT2VCB) &&
618                     (Vcb->Identifier.Size == sizeof(EXT2_VCB)))) {
619                 Status = STATUS_INVALID_PARAMETER;
620                 _SEH2_LEAVE;
621             }
622             Status = Ext2ProcessVolumeProperty(Vcb, Property, Length);
623         }
624 
625         if (NT_SUCCESS(Status)) {
626             IrpContext->Irp->IoStatus.Information = Length;
627         }
628 
629     } _SEH2_FINALLY {
630 
631         if (!IrpContext->ExceptionInProgress) {
632             Ext2CompleteIrpContext(IrpContext, Status);
633         }
634     } _SEH2_END;
635 
636     return Status;
637 }
638 
639 NTSTATUS
640 Ex2ProcessUserPerfStat(
641     IN PEXT2_IRP_CONTEXT    IrpContext,
642     IN PEXT2_QUERY_PERFSTAT QueryPerf,
643     IN ULONG                Length
644 )
645 {
646 
647 #ifndef __REACTOS__
648     PEXT2_VCB   Vcb = NULL;
649 #endif
650     PDEVICE_OBJECT  DeviceObject = NULL;
651 
652     BOOLEAN     GlobalDataResourceAcquired = FALSE;
653     NTSTATUS    Status = STATUS_SUCCESS;
654 
655     _SEH2_TRY {
656 
657         ASSERT(IrpContext != NULL);
658         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
659                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
660 
661         DeviceObject = IrpContext->DeviceObject;
662         if (IsExt2FsDevice(DeviceObject)) {
663 
664             if (QueryPerf->Magic != EXT2_QUERY_PERFSTAT_MAGIC) {
665                 Status = STATUS_INVALID_PARAMETER;
666                 _SEH2_LEAVE;
667             }
668 
669             if (QueryPerf->Command != IOCTL_APP_QUERY_PERFSTAT) {
670                 Status = STATUS_INVALID_PARAMETER;
671                 _SEH2_LEAVE;
672             }
673 
674             if (Length != EXT2_QUERY_PERFSTAT_SZV1 &&
675                 Length != EXT2_QUERY_PERFSTAT_SZV2) {
676                 Status = STATUS_INVALID_PARAMETER;
677                 _SEH2_LEAVE;
678             }
679 
680             ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
681             GlobalDataResourceAcquired = TRUE;
682 
683             if (Length == EXT2_QUERY_PERFSTAT_SZV2) {
684                 QueryPerf->Flags = EXT2_QUERY_PERFSTAT_VER2;
685                 QueryPerf->PerfStatV2 = Ext2Global->PerfStat;
686             } else {
687                 memcpy(&QueryPerf->PerfStatV1.Irps[0], &Ext2Global->PerfStat.Irps[0],
688                        FIELD_OFFSET(EXT2_PERF_STATISTICS_V1, Unit));
689                 memcpy(&QueryPerf->PerfStatV1.Unit, &Ext2Global->PerfStat.Unit,
690                        sizeof(EXT2_STAT_ARRAY_V1));
691                 memcpy(&QueryPerf->PerfStatV1.Current, &Ext2Global->PerfStat.Current,
692                        sizeof(EXT2_STAT_ARRAY_V1));
693                 memcpy(&QueryPerf->PerfStatV1.Size, &Ext2Global->PerfStat.Size,
694                        sizeof(EXT2_STAT_ARRAY_V1));
695                 memcpy(&QueryPerf->PerfStatV1.Total, &Ext2Global->PerfStat.Total,
696                        sizeof(EXT2_STAT_ARRAY_V1));
697             }
698 
699         } else {
700             Status = STATUS_INVALID_PARAMETER;
701             _SEH2_LEAVE;
702         }
703 
704         if (NT_SUCCESS(Status)) {
705             IrpContext->Irp->IoStatus.Information = Length;
706         }
707 
708     } _SEH2_FINALLY {
709 
710         if (GlobalDataResourceAcquired) {
711             ExReleaseResourceLite(&Ext2Global->Resource);
712         }
713 
714         if (!IrpContext->ExceptionInProgress) {
715             Ext2CompleteIrpContext(IrpContext, Status);
716         }
717     } _SEH2_END
718 
719     return Status;
720 }
721 
722 NTSTATUS
723 Ex2ProcessMountPoint(
724     IN PEXT2_IRP_CONTEXT    IrpContext,
725     IN PEXT2_MOUNT_POINT    MountPoint,
726     IN ULONG                Length
727 )
728 {
729     UNICODE_STRING  Link;
730     UNICODE_STRING  Target;
731     WCHAR           Buffer[] = L"\\DosDevices\\Global\\Z:";
732     NTSTATUS        status = STATUS_SUCCESS;
733 
734     PDEVICE_OBJECT  DeviceObject = NULL;
735 
736     _SEH2_TRY {
737 
738         ASSERT(IrpContext != NULL);
739         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
740                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
741 
742         DeviceObject = IrpContext->DeviceObject;
743         if (!IsExt2FsDevice(DeviceObject)) {
744             status = STATUS_INVALID_PARAMETER;
745             _SEH2_LEAVE;
746         }
747 
748         if (Length != sizeof(EXT2_MOUNT_POINT) ||
749             MountPoint->Magic != EXT2_APP_MOUNTPOINT_MAGIC) {
750             status = STATUS_INVALID_PARAMETER;
751             _SEH2_LEAVE;
752         }
753 
754         RtlInitUnicodeString(&Link, Buffer);
755         Buffer[12] = MountPoint->Link[0];
756 
757         switch (MountPoint->Command) {
758 
759         case APP_CMD_ADD_DOS_SYMLINK:
760             RtlInitUnicodeString(&Target, &MountPoint->Name[0]);
761             status = IoCreateSymbolicLink(&Link, &Target);
762             break;
763 
764         case APP_CMD_DEL_DOS_SYMLINK:
765             status = IoDeleteSymbolicLink(&Link);
766             break;
767 
768         default:
769             status = STATUS_INVALID_PARAMETER;
770         }
771 
772     } _SEH2_FINALLY {
773 
774         if (!IrpContext->ExceptionInProgress) {
775             Ext2CompleteIrpContext(IrpContext, status);
776         }
777     } _SEH2_END;
778 
779     return status;
780 }
781 
782 NTSTATUS
783 Ext2DeviceControl (IN PEXT2_IRP_CONTEXT IrpContext)
784 {
785     PIRP                Irp;
786     PIO_STACK_LOCATION  irpSp;
787     ULONG               code;
788     ULONG               length;
789     NTSTATUS            Status;
790 
791     ASSERT(IrpContext);
792 
793     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
794            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
795 
796     Irp = IrpContext->Irp;
797 
798     irpSp = IoGetCurrentIrpStackLocation(Irp);
799 
800     code = irpSp->Parameters.DeviceIoControl.IoControlCode;
801     length = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
802 
803     switch (code) {
804 
805     case IOCTL_APP_VOLUME_PROPERTY:
806         Status = Ext2ProcessUserProperty(
807                      IrpContext,
808                      Irp->AssociatedIrp.SystemBuffer,
809                      length
810                  );
811         break;
812 
813     case IOCTL_APP_QUERY_PERFSTAT:
814         Status = Ex2ProcessUserPerfStat(
815                      IrpContext,
816                      Irp->AssociatedIrp.SystemBuffer,
817                      length
818                  );
819         break;
820 
821     case IOCTL_APP_MOUNT_POINT:
822         Status = Ex2ProcessMountPoint(
823                      IrpContext,
824                      Irp->AssociatedIrp.SystemBuffer,
825                      length
826                  );
827         break;
828 
829 #if EXT2_UNLOAD
830     case IOCTL_PREPARE_TO_UNLOAD:
831         Status = Ext2PrepareToUnload(IrpContext);
832         break;
833 #endif
834     default:
835         Status = Ext2DeviceControlNormal(IrpContext);
836     }
837 
838     return Status;
839 }
840