1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             dispatch.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, Ext2QueueRequest)
22 #pragma alloc_text(PAGE, Ext2DeQueueRequest)
23 #endif
24 
25 /*
26  *  Ext2OplockComplete
27  *
28  *    callback routine of FsRtlCheckOplock when an oplock break has
29  *    completed, allowing an Irp to resume execution.
30  *
31  *  Arguments:
32  *
33  *    Context:  the IrpContext to be queued
34  *    Irp:      the I/O request packet
35  *
36  *  Return Value:
37  *    N/A
38  */
39 
40 #ifdef __REACTOS__
41 VOID NTAPI
42 #else
43 VOID
44 #endif
45 Ext2OplockComplete (
46     IN PVOID Context,
47     IN PIRP Irp
48 )
49 {
50     //
51     //  Check on the return value in the Irp.
52     //
53 
54     if (Irp->IoStatus.Status == STATUS_SUCCESS) {
55 
56         //
57         //  queue the Irp context in the workqueue.
58         //
59 
60         Ext2QueueRequest((PEXT2_IRP_CONTEXT)Context);
61 
62     } else {
63 
64         //
65         //  complete the request in case of failure
66         //
67 
68         Ext2CompleteIrpContext( (PEXT2_IRP_CONTEXT) Context,
69                                 Irp->IoStatus.Status );
70     }
71 
72     return;
73 }
74 
75 
76 /*
77  *  Ext2LockIrp
78  *
79  *    performs buffer locking if we need pend the process of the Irp
80  *
81  *  Arguments:
82  *    Context: the irp context
83  *    Irp:     the I/O request packet.
84  *
85  *  Return Value:
86  *    N/A
87  */
88 
89 #ifdef __REACTOS__
90 VOID NTAPI
91 #else
92 VOID
93 #endif
94 Ext2LockIrp (
95     IN PVOID Context,
96     IN PIRP Irp
97 )
98 {
99     PIO_STACK_LOCATION IrpSp;
100     PEXT2_IRP_CONTEXT IrpContext;
101 
102     if (Irp == NULL) {
103         return;
104     }
105 
106     IrpSp = IoGetCurrentIrpStackLocation(Irp);
107 
108     IrpContext = (PEXT2_IRP_CONTEXT) Context;
109 
110     if ( IrpContext->MajorFunction == IRP_MJ_READ ||
111             IrpContext->MajorFunction == IRP_MJ_WRITE ) {
112 
113         //
114         //  lock the user's buffer to MDL, if the I/O is bufferred
115         //
116 
117         if (!IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
118 
119             Ext2LockUserBuffer( Irp, IrpSp->Parameters.Write.Length,
120                                 (IrpContext->MajorFunction == IRP_MJ_READ) ?
121                                 IoWriteAccess : IoReadAccess );
122         }
123 
124     } else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
125                && IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
126 
127         ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryDirectory.Length;
128         Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
129 
130     } else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
131 
132         ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryEa.Length;
133         Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
134 
135     } else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
136         ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.SetEa.Length;
137         Ext2LockUserBuffer(Irp, Length, IoReadAccess);
138 
139     } else if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
140                 (IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) ) {
141         PEXTENDED_IO_STACK_LOCATION EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
142         if ( (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
143                 (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS) ||
144                 (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTER_BASE) ) {
145             ULONG Length = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
146             Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
147         }
148     }
149 
150     //  Mark the request as pending status
151 
152     IoMarkIrpPending( Irp );
153 
154     return;
155 }
156 
157 NTSTATUS
158 Ext2QueueRequest (IN PEXT2_IRP_CONTEXT IrpContext)
159 {
160     ASSERT(IrpContext);
161 
162     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
163            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
164 
165     /* set the flags of "can wait" and "queued" */
166     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
167     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
168 
169     /* make sure the buffer is kept valid in system context */
170     Ext2LockIrp(IrpContext, IrpContext->Irp);
171 
172     /* initialize workite*/
173     ExInitializeWorkItem(
174         &IrpContext->WorkQueueItem,
175         Ext2DeQueueRequest,
176         IrpContext );
177 
178     /* dispatch it */
179     ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
180 
181     return STATUS_PENDING;
182 }
183 
184 
185 #ifdef __REACTOS__
186 VOID NTAPI
187 #else
188 VOID
189 #endif
190 Ext2DeQueueRequest (IN PVOID Context)
191 {
192     PEXT2_IRP_CONTEXT IrpContext;
193 
194     IrpContext = (PEXT2_IRP_CONTEXT) Context;
195 
196     ASSERT(IrpContext);
197 
198     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
199            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
200 
201     _SEH2_TRY {
202 
203         _SEH2_TRY {
204 
205             FsRtlEnterFileSystem();
206 
207             if (!IrpContext->IsTopLevel) {
208                 IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
209             }
210 
211             Ext2DispatchRequest(IrpContext);
212 
213         } _SEH2_EXCEPT (Ext2ExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
214 
215             Ext2ExceptionHandler(IrpContext);
216         } _SEH2_END;
217 
218     } _SEH2_FINALLY {
219 
220         IoSetTopLevelIrp(NULL);
221 
222         FsRtlExitFileSystem();
223     } _SEH2_END;
224 }
225 
226 
227 NTSTATUS
228 Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext)
229 {
230     ASSERT(IrpContext);
231 
232     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
233            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
234 
235     switch (IrpContext->MajorFunction) {
236 
237     case IRP_MJ_CREATE:
238         return Ext2Create(IrpContext);
239 
240     case IRP_MJ_CLOSE:
241         return Ext2Close(IrpContext);
242 
243     case IRP_MJ_READ:
244         return Ext2Read(IrpContext);
245 
246     case IRP_MJ_WRITE:
247         return Ext2Write(IrpContext);
248 
249     case IRP_MJ_FLUSH_BUFFERS:
250         return Ext2Flush(IrpContext);
251 
252     case IRP_MJ_QUERY_INFORMATION:
253         return Ext2QueryFileInformation(IrpContext);
254 
255     case IRP_MJ_SET_INFORMATION:
256         return Ext2SetFileInformation(IrpContext);
257 
258     case IRP_MJ_QUERY_VOLUME_INFORMATION:
259         return Ext2QueryVolumeInformation(IrpContext);
260 
261     case IRP_MJ_SET_VOLUME_INFORMATION:
262         return Ext2SetVolumeInformation(IrpContext);
263 
264     case IRP_MJ_DIRECTORY_CONTROL:
265         return Ext2DirectoryControl(IrpContext);
266 
267     case IRP_MJ_FILE_SYSTEM_CONTROL:
268         return Ext2FileSystemControl(IrpContext);
269 
270     case IRP_MJ_DEVICE_CONTROL:
271         return Ext2DeviceControl(IrpContext);
272 
273     case IRP_MJ_LOCK_CONTROL:
274         return Ext2LockControl(IrpContext);
275 
276     case IRP_MJ_CLEANUP:
277         return Ext2Cleanup(IrpContext);
278 
279     case IRP_MJ_SHUTDOWN:
280         return Ext2ShutDown(IrpContext);
281 
282 	case IRP_MJ_QUERY_EA:
283 		return Ext2QueryEa(IrpContext);
284 
285 	case IRP_MJ_SET_EA:
286 		return Ext2SetEa(IrpContext);
287 
288 #if (_WIN32_WINNT >= 0x0500)
289     case IRP_MJ_PNP:
290         return Ext2Pnp(IrpContext);
291 #endif //(_WIN32_WINNT >= 0x0500)
292     default:
293         DEBUG(DL_ERR, ( "Ext2DispatchRequest: Unexpected major function: %xh\n",
294                         IrpContext->MajorFunction));
295 
296         Ext2CompleteIrpContext(IrpContext, STATUS_DRIVER_INTERNAL_ERROR);
297 
298         return STATUS_DRIVER_INTERNAL_ERROR;
299     }
300 }
301 
302 
303 #ifdef __REACTOS__
304 NTSTATUS NTAPI
305 #else
306 NTSTATUS
307 #endif
308 Ext2BuildRequest (PDEVICE_OBJECT   DeviceObject, PIRP Irp)
309 {
310     BOOLEAN             AtIrqlPassiveLevel = FALSE;
311     BOOLEAN             IsTopLevelIrp = FALSE;
312     PEXT2_IRP_CONTEXT   IrpContext = NULL;
313     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
314 
315     _SEH2_TRY {
316 
317         _SEH2_TRY {
318 
319 #if EXT2_DEBUG
320             Ext2DbgPrintCall(DeviceObject, Irp);
321 #endif
322 
323             AtIrqlPassiveLevel = (KeGetCurrentIrql() == PASSIVE_LEVEL);
324 
325             if (AtIrqlPassiveLevel) {
326                 FsRtlEnterFileSystem();
327             }
328 
329             if (!IoGetTopLevelIrp()) {
330                 IsTopLevelIrp = TRUE;
331                 IoSetTopLevelIrp(Irp);
332             }
333 
334             IrpContext = Ext2AllocateIrpContext(DeviceObject, Irp);
335 
336             if (!IrpContext) {
337 
338                 Status = STATUS_INSUFFICIENT_RESOURCES;
339                 Irp->IoStatus.Status = Status;
340 
341                 Ext2CompleteRequest(Irp, TRUE, IO_NO_INCREMENT);
342 
343             } else {
344 
345                 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
346                         !AtIrqlPassiveLevel) {
347 
348                     DbgBreak();
349                 }
350 
351                 Status = Ext2DispatchRequest(IrpContext);
352             }
353         } _SEH2_EXCEPT (Ext2ExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
354 
355             Status = Ext2ExceptionHandler(IrpContext);
356         } _SEH2_END;
357 
358     } _SEH2_FINALLY {
359 
360         if (IsTopLevelIrp) {
361             IoSetTopLevelIrp(NULL);
362         }
363 
364         if (AtIrqlPassiveLevel) {
365             FsRtlExitFileSystem();
366         }
367     } _SEH2_END;
368 
369     return Status;
370 }
371