1 /* 2 * PROJECT: ReactOS Named Pipe FileSystem 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/filesystems/npfs/statesup.c 5 * PURPOSE: Pipes State Support 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "npfs.h" 12 13 // File ID number for NPFS bugchecking support 14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_STATESUP) 15 16 /* FUNCTIONS ******************************************************************/ 17 18 VOID 19 NTAPI 20 NpCancelListeningQueueIrp(IN PDEVICE_OBJECT DeviceObject, 21 IN PIRP Irp) 22 { 23 IoReleaseCancelSpinLock(Irp->CancelIrql); 24 25 FsRtlEnterFileSystem(); 26 NpAcquireExclusiveVcb(); 27 28 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 29 30 NpReleaseVcb(); 31 FsRtlExitFileSystem(); 32 33 Irp->IoStatus.Status = STATUS_CANCELLED; 34 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT); 35 } 36 37 NTSTATUS 38 NTAPI 39 NpSetConnectedPipeState(IN PNP_CCB Ccb, 40 IN PFILE_OBJECT FileObject, 41 IN PLIST_ENTRY List) 42 { 43 PLIST_ENTRY NextEntry; 44 PIRP Irp; 45 46 ASSERT(Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE); 47 48 Ccb->ReadMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_BYTE_STREAM_MODE; 49 Ccb->CompletionMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_QUEUE_OPERATION; 50 Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE; 51 Ccb->FileObject[FILE_PIPE_CLIENT_END] = FileObject; 52 53 NpSetFileObject(FileObject, Ccb, Ccb->NonPagedCcb, FALSE); 54 55 while (!IsListEmpty(&Ccb->IrpList)) 56 { 57 NextEntry = RemoveHeadList(&Ccb->IrpList); 58 59 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 60 61 if (IoSetCancelRoutine(Irp, NULL)) 62 { 63 Irp->IoStatus.Status = STATUS_SUCCESS; 64 InsertTailList(List, NextEntry); 65 } 66 else 67 { 68 InitializeListHead(NextEntry); 69 } 70 } 71 72 return STATUS_SUCCESS; 73 } 74 75 NTSTATUS 76 NTAPI 77 NpSetDisconnectedPipeState(IN PNP_CCB Ccb, 78 IN PLIST_ENTRY List) 79 { 80 PIRP Irp; 81 PNP_NONPAGED_CCB NonPagedCcb; 82 NTSTATUS Status; 83 PLIST_ENTRY NextEntry; 84 PNP_EVENT_BUFFER EventBuffer; 85 86 NonPagedCcb = Ccb->NonPagedCcb; 87 88 switch (Ccb->NamedPipeState) 89 { 90 case FILE_PIPE_DISCONNECTED_STATE: 91 Status = STATUS_PIPE_DISCONNECTED; 92 break; 93 94 case FILE_PIPE_LISTENING_STATE: 95 while (!IsListEmpty(&Ccb->IrpList)) 96 { 97 NextEntry = RemoveHeadList(&Ccb->IrpList); 98 99 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 100 101 if (IoSetCancelRoutine(Irp, NULL)) 102 { 103 Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; 104 InsertTailList(List, NextEntry); 105 } 106 else 107 { 108 InitializeListHead(NextEntry); 109 } 110 } 111 112 Status = STATUS_SUCCESS; 113 break; 114 115 case FILE_PIPE_CONNECTED_STATE: 116 117 EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; 118 119 while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) 120 { 121 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); 122 if (Irp) 123 { 124 Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; 125 InsertTailList(List, &Irp->Tail.Overlay.ListEntry); 126 } 127 } 128 129 while (Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState != Empty) 130 { 131 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_OUTBOUND], FALSE, List); 132 if (Irp) 133 { 134 Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; 135 InsertTailList(List, &Irp->Tail.Overlay.ListEntry); 136 } 137 } 138 139 if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); 140 141 // drop down on purpose... queue will be empty so flush code is nop 142 ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); 143 144 case FILE_PIPE_CLOSING_STATE: 145 146 EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; 147 148 while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) 149 { 150 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); 151 if (Irp) 152 { 153 Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; 154 InsertTailList(List, &Irp->Tail.Overlay.ListEntry); 155 } 156 } 157 158 ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); 159 160 NpDeleteEventTableEntry(&NpVcb->EventTable, EventBuffer); 161 NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END] = NULL; 162 163 NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); 164 Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; 165 166 NpUninitializeSecurity(Ccb); 167 168 if (Ccb->ClientSession) 169 { 170 ExFreePool(Ccb->ClientSession); 171 Ccb->ClientSession = NULL; 172 } 173 174 Status = STATUS_SUCCESS; 175 break; 176 177 default: 178 NpBugCheck(Ccb->NamedPipeState, 0, 0); 179 break; 180 } 181 182 Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE; 183 return Status; 184 } 185 186 NTSTATUS 187 NTAPI 188 NpSetListeningPipeState(IN PNP_CCB Ccb, 189 IN PIRP Irp, 190 IN PLIST_ENTRY List) 191 { 192 NTSTATUS Status; 193 194 switch (Ccb->NamedPipeState) 195 { 196 case FILE_PIPE_DISCONNECTED_STATE: 197 198 Status = NpCancelWaiter(&NpVcb->WaitQueue, 199 &Ccb->Fcb->FullName, 200 STATUS_SUCCESS, 201 List); 202 if (!NT_SUCCESS(Status)) return Status; 203 204 // 205 // Drop down on purpose 206 // 207 208 case FILE_PIPE_LISTENING_STATE: 209 210 if (Ccb->CompletionMode[FILE_PIPE_SERVER_END] == FILE_PIPE_COMPLETE_OPERATION) 211 { 212 Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE; 213 return STATUS_PIPE_LISTENING; 214 } 215 216 IoSetCancelRoutine(Irp, NpCancelListeningQueueIrp); 217 if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) 218 { 219 return STATUS_CANCELLED; 220 } 221 222 Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE; 223 IoMarkIrpPending(Irp); 224 InsertTailList(&Ccb->IrpList, &Irp->Tail.Overlay.ListEntry); 225 return STATUS_PENDING; 226 227 case FILE_PIPE_CONNECTED_STATE: 228 Status = STATUS_PIPE_CONNECTED; 229 break; 230 231 case FILE_PIPE_CLOSING_STATE: 232 Status = STATUS_PIPE_CLOSING; 233 break; 234 235 default: 236 NpBugCheck(Ccb->NamedPipeState, 0, 0); 237 break; 238 } 239 240 return Status; 241 } 242 243 NTSTATUS 244 NTAPI 245 NpSetClosingPipeState(IN PNP_CCB Ccb, 246 IN PIRP Irp, 247 IN ULONG NamedPipeEnd, 248 IN PLIST_ENTRY List) 249 { 250 PNP_NONPAGED_CCB NonPagedCcb; 251 PNP_FCB Fcb; 252 PLIST_ENTRY NextEntry; 253 PNP_DATA_QUEUE ReadQueue, WriteQueue, DataQueue; 254 PNP_EVENT_BUFFER EventBuffer; 255 PIRP ListIrp; 256 257 NonPagedCcb = Ccb->NonPagedCcb; 258 Fcb = Ccb->Fcb; 259 260 switch (Ccb->NamedPipeState) 261 { 262 case FILE_PIPE_LISTENING_STATE: 263 264 ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); 265 266 while (!IsListEmpty(&Ccb->IrpList)) 267 { 268 NextEntry = RemoveHeadList(&Ccb->IrpList); 269 270 ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 271 272 if (IoSetCancelRoutine(ListIrp, NULL)) 273 { 274 ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; 275 InsertTailList(List, NextEntry); 276 } 277 else 278 { 279 InitializeListHead(NextEntry); 280 } 281 } 282 283 // Drop on purpose 284 285 case FILE_PIPE_DISCONNECTED_STATE: 286 287 ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); 288 289 NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); 290 Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; 291 292 NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); 293 Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; 294 295 NpDeleteCcb(Ccb, List); 296 if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); 297 break; 298 299 case FILE_PIPE_CLOSING_STATE: 300 301 if (NamedPipeEnd == FILE_PIPE_SERVER_END) 302 { 303 DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; 304 } 305 else 306 { 307 DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; 308 } 309 310 NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); 311 Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; 312 313 NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); 314 Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; 315 316 while (DataQueue->QueueState != Empty) 317 { 318 ListIrp = NpRemoveDataQueueEntry(DataQueue, FALSE, List); 319 if (ListIrp) 320 { 321 ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; 322 InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); 323 } 324 } 325 326 NpUninitializeSecurity(Ccb); 327 328 if (Ccb->ClientSession) 329 { 330 ExFreePool(Ccb->ClientSession); 331 Ccb->ClientSession = NULL; 332 } 333 334 NpDeleteCcb(Ccb, List); 335 if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); 336 break; 337 338 case FILE_PIPE_CONNECTED_STATE: 339 340 if (NamedPipeEnd == FILE_PIPE_SERVER_END) 341 { 342 ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; 343 WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; 344 345 NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); 346 Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; 347 } 348 else 349 { 350 ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; 351 WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; 352 353 NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); 354 Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; 355 } 356 357 EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd]; 358 359 Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE; 360 361 while (ReadQueue->QueueState != Empty) 362 { 363 ListIrp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List); 364 if (ListIrp) 365 { 366 ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; 367 InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); 368 } 369 } 370 371 while (WriteQueue->QueueState == ReadEntries) 372 { 373 ListIrp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List); 374 if (ListIrp) 375 { 376 ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; 377 InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); 378 } 379 } 380 381 if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); 382 break; 383 384 default: 385 NpBugCheck(Ccb->NamedPipeState, 0, 0); 386 break; 387 } 388 return STATUS_SUCCESS; 389 } 390 391 /* EOF */ 392