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