xref: /reactos/drivers/filesystems/ext2/src/except.c (revision b36d9bd9)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             except.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
21 Ext2ExceptionFilter (
22     IN PEXT2_IRP_CONTEXT    IrpContext,
23     IN PEXCEPTION_POINTERS  ExceptionPointer
24 )
25 {
26     NTSTATUS Status = EXCEPTION_EXECUTE_HANDLER;
27     NTSTATUS ExceptionCode;
28     PEXCEPTION_RECORD ExceptRecord;
29 
30     ExceptRecord = ExceptionPointer->ExceptionRecord;
31     ExceptionCode = ExceptRecord->ExceptionCode;
32 
33     DbgPrint("-------------------------------------------------------------\n");
34     DbgPrint("Exception happends in Ext2Fsd (code %xh):\n", ExceptionCode);
35     DbgPrint(".exr %p;.cxr %p;\n", ExceptionPointer->ExceptionRecord,
36              ExceptionPointer->ContextRecord);
37     DbgPrint("-------------------------------------------------------------\n");
38 
39     DbgBreak();
40 
41     //
42     // Check IrpContext is valid or not
43     //
44 
45     if (IrpContext) {
46         if ((IrpContext->Identifier.Type != EXT2ICX) ||
47             (IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
48             DbgBreak();
49             IrpContext = NULL;
50         } else if (IrpContext->DeviceObject) {
51             PEXT2_VCB Vcb = NULL;
52             Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
53             if (NULL == Vcb) {
54                 Status = EXCEPTION_EXECUTE_HANDLER;
55             } else {
56                 if (Vcb->Identifier.Type == EXT2VCB && !IsMounted(Vcb)) {
57                     Status = EXCEPTION_EXECUTE_HANDLER;
58                 }
59             }
60         }
61     } else {
62         if (FsRtlIsNtstatusExpected(ExceptionCode)) {
63             return EXCEPTION_EXECUTE_HANDLER;
64         } else {
65             Ext2BugCheck( EXT2_BUGCHK_EXCEPT, (ULONG_PTR)ExceptRecord,
66                           (ULONG_PTR)ExceptionPointer->ContextRecord,
67                           (ULONG_PTR)ExceptRecord->ExceptionAddress );
68         }
69     }
70 
71     if (IrpContext) {
72         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
73     }
74 
75     if ( Status == EXCEPTION_EXECUTE_HANDLER ||
76          FsRtlIsNtstatusExpected(ExceptionCode)) {
77         //
78         // If the exception is expected execute our handler
79         //
80 
81         DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Catching exception %xh\n",
82                          ExceptionCode));
83 
84         Status = EXCEPTION_EXECUTE_HANDLER;
85 
86         if (IrpContext) {
87             IrpContext->ExceptionInProgress = TRUE;
88             IrpContext->ExceptionCode = ExceptionCode;
89         }
90 
91     } else  {
92 
93         //
94         // Continue search for an higher level exception handler
95         //
96 
97         DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Passing on exception %#x\n",
98                         ExceptionCode));
99 
100         Status = EXCEPTION_CONTINUE_SEARCH;
101 
102         if (IrpContext) {
103             Ext2FreeIrpContext(IrpContext);
104         }
105     }
106 
107     return Status;
108 }
109 
110 
111 NTSTATUS
112 Ext2ExceptionHandler (IN PEXT2_IRP_CONTEXT IrpContext)
113 {
114     NTSTATUS Status;
115 
116     if (IrpContext) {
117 
118         if ( (IrpContext->Identifier.Type != EXT2ICX) ||
119                 (IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
120             DbgBreak();
121             return STATUS_UNSUCCESSFUL;
122         }
123 
124         Status = IrpContext->ExceptionCode;
125 
126         if (IrpContext->Irp) {
127 
128             //
129             // Check if this error is a result of user actions
130             //
131 
132             PEXT2_VCB  Vcb = NULL;
133             PIRP Irp = IrpContext->Irp;
134             PIO_STACK_LOCATION IrpSp;
135 
136             IrpSp = IoGetCurrentIrpStackLocation(Irp);
137             Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
138 
139             if (NULL == Vcb) {
140                 Status = STATUS_INVALID_PARAMETER;
141             } else if (Vcb->Identifier.Type != EXT2VCB) {
142                 Status = STATUS_INVALID_PARAMETER;
143             } else if (!IsMounted(Vcb)) {
144                 if (IsFlagOn(Vcb->Flags, VCB_DEVICE_REMOVED)) {
145                     Status = STATUS_NO_SUCH_DEVICE;
146                 } else {
147                     Status = STATUS_VOLUME_DISMOUNTED;
148                 }
149             } else {
150 
151                 /* queue it again if our request is at top level */
152                 if (IrpContext->IsTopLevel &&
153                         ((Status == STATUS_CANT_WAIT) ||
154                          ((Status == STATUS_VERIFY_REQUIRED) &&
155                           (KeGetCurrentIrql() >= APC_LEVEL)))) {
156 
157                     Status = Ext2QueueRequest(IrpContext);
158                 }
159             }
160 
161             if (Status == STATUS_PENDING) {
162                 goto errorout;
163             }
164 
165             Irp->IoStatus.Status = Status;
166 
167             if (IoIsErrorUserInduced(Status)) {
168 
169                 //
170                 //  Now we will generate a pop-up to user
171                 //
172 
173                 PDEVICE_OBJECT RealDevice;
174                 PVPB           Vpb = NULL;
175                 PETHREAD       Thread;
176 
177                 if (IrpSp->FileObject != NULL) {
178                     Vpb = IrpSp->FileObject->Vpb;
179                 }
180 
181                 //
182                 // Get the initial thread
183                 //
184 
185                 Thread = Irp->Tail.Overlay.Thread;
186                 RealDevice = IoGetDeviceToVerify( Thread );
187 
188                 if (RealDevice == NULL) {
189                     //
190                     // Get current thread
191                     //
192 
193                     Thread = PsGetCurrentThread();
194                     RealDevice = IoGetDeviceToVerify( Thread );
195 
196                     ASSERT( RealDevice != NULL );
197                 }
198 
199                 Status =  IrpContext->ExceptionCode;
200 
201                 if (RealDevice != NULL) {
202 
203                     if (IrpContext->ExceptionCode == STATUS_VERIFY_REQUIRED) {
204 
205                         Status = IoVerifyVolume (RealDevice, FALSE);
206 
207                         ExAcquireResourceSharedLite(&Vcb->MainResource, TRUE);
208                         if (NT_SUCCESS(Status) && (!IsMounted(Vcb) ||
209                                                    IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))) {
210                             Status = STATUS_WRONG_VOLUME;
211                         }
212                         ExReleaseResourceLite(&Vcb->MainResource);
213 
214                         if (Ext2CheckDismount(IrpContext, Vcb, FALSE)) {
215                             Ext2CompleteIrpContext( IrpContext, STATUS_VOLUME_DISMOUNTED);
216                             Status = STATUS_VOLUME_DISMOUNTED;
217                             Irp = NULL;
218                             goto errorout;
219                         }
220 
221                         if ( (IrpContext->MajorFunction == IRP_MJ_CREATE) &&
222                                 (IrpContext->FileObject->RelatedFileObject == NULL) &&
223                                 ((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {
224 
225                             Irp->IoStatus.Information = IO_REMOUNT;
226 
227                             Ext2CompleteIrpContext( IrpContext, STATUS_REPARSE);
228                             Status = STATUS_REPARSE;
229                             Irp = NULL;
230                         }
231 
232                         if (Irp) {
233 
234                             if (!NT_SUCCESS(Status)) {
235                                 IoSetHardErrorOrVerifyDevice(Irp, RealDevice);
236                                 ASSERT (STATUS_VERIFY_REQUIRED != Status);
237                                 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
238                             }
239 
240                             Status = Ext2QueueRequest(IrpContext);
241                         }
242 
243                         goto errorout;
244 
245                     } else {
246 
247                         Status = STATUS_PENDING;
248 
249                         IoMarkIrpPending( Irp );
250                         IoRaiseHardError( Irp, Vpb, RealDevice );
251                         IoSetDeviceToVerify( Thread, NULL );
252                         goto release_context;
253                     }
254                 }
255             }
256 
257             Ext2CompleteRequest(Irp, FALSE, IO_NO_INCREMENT);
258         }
259 
260 release_context:
261 
262         Ext2FreeIrpContext(IrpContext);
263 
264     } else {
265 
266         Status = STATUS_INVALID_PARAMETER;
267     }
268 
269 errorout:
270 
271     return Status;
272 }
273 
274