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