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