2faef1c70a8d9ecaef5b6befe4a00aae87f045c2
[reactos.git] / reactos / drivers / fs / np / create.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/create.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #include "npfs.h"
15
16 /* FUNCTIONS *****************************************************************/
17
18 static PNPFS_PIPE
19 NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt,
20 PUNICODE_STRING PipeName)
21 {
22 PLIST_ENTRY CurrentEntry;
23 PNPFS_PIPE Pipe;
24
25 CurrentEntry = DeviceExt->PipeListHead.Flink;
26 while (CurrentEntry != &DeviceExt->PipeListHead)
27 {
28 Pipe = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE, PipeListEntry);
29 if (RtlCompareUnicodeString(PipeName,
30 &Pipe->PipeName,
31 TRUE) == 0)
32 {
33 DPRINT("<%wZ> = <%wZ>\n", PipeName, &Pipe->PipeName);
34 return Pipe;
35 }
36
37 CurrentEntry = CurrentEntry->Flink;
38 }
39
40 return NULL;
41 }
42
43
44 static PNPFS_FCB
45 NpfsFindListeningServerInstance(PNPFS_PIPE Pipe)
46 {
47 PLIST_ENTRY CurrentEntry;
48 PNPFS_WAITER_ENTRY Waiter;
49 KIRQL oldIrql;
50 PIRP Irp;
51
52 CurrentEntry = Pipe->WaiterListHead.Flink;
53 while (CurrentEntry != &Pipe->WaiterListHead)
54 {
55 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
56 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
57 if (Waiter->Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
58 {
59 DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
60
61 IoAcquireCancelSpinLock(&oldIrql);
62 if (!Irp->Cancel)
63 {
64 IoSetCancelRoutine(Irp, NULL);
65 IoReleaseCancelSpinLock(oldIrql);
66 return Waiter->Fcb;
67 }
68 IoReleaseCancelSpinLock(oldIrql);
69 }
70
71 CurrentEntry = CurrentEntry->Flink;
72 }
73
74 return NULL;
75 }
76
77
78 static VOID
79 NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe,
80 PNPFS_FCB Fcb)
81 {
82 PLIST_ENTRY CurrentEntry;
83 PNPFS_WAITER_ENTRY Waiter;
84 PIRP Irp;
85
86 CurrentEntry = Pipe->WaiterListHead.Flink;
87 while (CurrentEntry != &Pipe->WaiterListHead)
88 {
89 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
90 if (Waiter->Fcb == Fcb)
91 {
92 DPRINT("Server found! Fcb %p\n", Waiter->Fcb);
93
94 RemoveEntryList(&Waiter->Entry);
95 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
96 Irp->IoStatus.Status = STATUS_SUCCESS;
97 Irp->IoStatus.Information = 0;
98 IoCompleteRequest(Irp, IO_NO_INCREMENT);
99 break;
100 }
101 CurrentEntry = CurrentEntry->Flink;
102 }
103 }
104
105
106 NTSTATUS STDCALL
107 NpfsCreate(PDEVICE_OBJECT DeviceObject,
108 PIRP Irp)
109 {
110 PEXTENDED_IO_STACK_LOCATION IoStack;
111 PFILE_OBJECT FileObject;
112 PNPFS_PIPE Pipe;
113 PNPFS_FCB ClientFcb;
114 PNPFS_FCB ServerFcb = NULL;
115 PNPFS_DEVICE_EXTENSION DeviceExt;
116 BOOLEAN SpecialAccess;
117 ACCESS_MASK DesiredAccess;
118
119 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
120
121 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
122 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
123 FileObject = IoStack->FileObject;
124 DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
125 DPRINT("FileObject %p\n", FileObject);
126 DPRINT("FileName %wZ\n", &FileObject->FileName);
127
128 Irp->IoStatus.Information = 0;
129
130 SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES);
131 if (SpecialAccess)
132 {
133 DPRINT("NpfsCreate() open client end for special use!\n");
134 }
135
136 /*
137 * Step 1. Find the pipe we're trying to open.
138 */
139 KeLockMutex(&DeviceExt->PipeListLock);
140 Pipe = NpfsFindPipe(DeviceExt,
141 &FileObject->FileName);
142 if (Pipe == NULL)
143 {
144 /* Not found, bail out with error. */
145 DPRINT("No pipe found!\n");
146 KeUnlockMutex(&DeviceExt->PipeListLock);
147 Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
148 IoCompleteRequest(Irp, IO_NO_INCREMENT);
149 return STATUS_OBJECT_NAME_NOT_FOUND;
150 }
151
152 KeUnlockMutex(&DeviceExt->PipeListLock);
153
154 /*
155 * Acquire the lock for FCB lists. From now on no modifications to the
156 * FCB lists are allowed, because it can cause various misconsistencies.
157 */
158 KeLockMutex(&Pipe->FcbListLock);
159
160 /*
161 * Step 2. Create the client FCB.
162 */
163 ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
164 if (ClientFcb == NULL)
165 {
166 DPRINT("No memory!\n");
167 KeUnlockMutex(&Pipe->FcbListLock);
168 Irp->IoStatus.Status = STATUS_NO_MEMORY;
169 IoCompleteRequest(Irp, IO_NO_INCREMENT);
170 return STATUS_NO_MEMORY;
171 }
172
173 ClientFcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
174 ClientFcb->Pipe = Pipe;
175 ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
176 ClientFcb->OtherSide = NULL;
177 ClientFcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
178 InitializeListHead(&ClientFcb->ReadRequestListHead);
179
180 DPRINT("Fcb: %x\n", ClientFcb);
181
182 /* Initialize data list. */
183 if (Pipe->OutboundQuota)
184 {
185 ClientFcb->Data = ExAllocatePool(PagedPool, Pipe->OutboundQuota);
186 if (ClientFcb->Data == NULL)
187 {
188 DPRINT("No memory!\n");
189 ExFreePool(ClientFcb);
190 KeUnlockMutex(&Pipe->FcbListLock);
191 Irp->IoStatus.Status = STATUS_NO_MEMORY;
192 IoCompleteRequest(Irp, IO_NO_INCREMENT);
193 return STATUS_NO_MEMORY;
194 }
195 }
196 else
197 {
198 ClientFcb->Data = NULL;
199 }
200
201 ClientFcb->ReadPtr = ClientFcb->Data;
202 ClientFcb->WritePtr = ClientFcb->Data;
203 ClientFcb->ReadDataAvailable = 0;
204 ClientFcb->WriteQuotaAvailable = Pipe->OutboundQuota;
205 ClientFcb->MaxDataLength = Pipe->OutboundQuota;
206 ExInitializeFastMutex(&ClientFcb->DataListLock);
207 KeInitializeEvent(&ClientFcb->ConnectEvent, SynchronizationEvent, FALSE);
208 KeInitializeEvent(&ClientFcb->ReadEvent, SynchronizationEvent, FALSE);
209 KeInitializeEvent(&ClientFcb->WriteEvent, SynchronizationEvent, FALSE);
210
211
212 /*
213 * Step 3. Search for listening server FCB.
214 */
215
216 if (!SpecialAccess)
217 {
218 /*
219 * WARNING: Point of no return! Once we get the server FCB it's
220 * possible that we completed a wait request and so we have to
221 * complete even this request.
222 */
223
224 ServerFcb = NpfsFindListeningServerInstance(Pipe);
225 if (ServerFcb == NULL)
226 {
227 PLIST_ENTRY CurrentEntry;
228 PNPFS_FCB Fcb;
229
230 /*
231 * If no waiting server FCB was found then try to pick
232 * one of the listing server FCB on the pipe.
233 */
234
235 CurrentEntry = Pipe->ServerFcbListHead.Flink;
236 while (CurrentEntry != &Pipe->ServerFcbListHead)
237 {
238 Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, FcbListEntry);
239 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
240 {
241 ServerFcb = Fcb;
242 break;
243 }
244 CurrentEntry = CurrentEntry->Flink;
245 }
246
247 /*
248 * No one is listening to me?! I'm so lonely... :(
249 */
250
251 if (ServerFcb == NULL)
252 {
253 /* Not found, bail out with error for FILE_OPEN requests. */
254 DPRINT("No listening server fcb found!\n");
255 if (ClientFcb->Data)
256 ExFreePool(ClientFcb->Data);
257 KeUnlockMutex(&Pipe->FcbListLock);
258 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
259 IoCompleteRequest(Irp, IO_NO_INCREMENT);
260 return STATUS_PIPE_BUSY;
261 }
262 }
263 else
264 {
265 /* Signal the server thread and remove it from the waiter list */
266 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
267 NpfsSignalAndRemoveListeningServerInstance(Pipe, ServerFcb);
268 }
269 }
270 else if (IsListEmpty(&Pipe->ServerFcbListHead))
271 {
272 DPRINT("No server fcb found!\n");
273 KeUnlockMutex(&Pipe->FcbListLock);
274 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
275 IoCompleteRequest(Irp, IO_NO_INCREMENT);
276 return STATUS_UNSUCCESSFUL;
277 }
278
279 /*
280 * Step 4. Add the client FCB to a list and connect it if possible.
281 */
282
283 /* Add the client FCB to the pipe FCB list. */
284 InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
285
286 /* Connect to listening server side */
287 if (ServerFcb)
288 {
289 ClientFcb->OtherSide = ServerFcb;
290 ServerFcb->OtherSide = ClientFcb;
291 ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
292 ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
293 }
294
295 KeUnlockMutex(&Pipe->FcbListLock);
296
297 FileObject->FsContext = ClientFcb;
298
299 Irp->IoStatus.Status = STATUS_SUCCESS;
300 IoCompleteRequest(Irp, IO_NO_INCREMENT);
301
302 DPRINT("Success!\n");
303
304 return STATUS_SUCCESS;
305 }
306
307
308 NTSTATUS STDCALL
309 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
310 PIRP Irp)
311 {
312 PEXTENDED_IO_STACK_LOCATION IoStack;
313 PFILE_OBJECT FileObject;
314 PNPFS_DEVICE_EXTENSION DeviceExt;
315 PNPFS_PIPE Pipe;
316 PNPFS_FCB Fcb;
317 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
318 BOOLEAN NewPipe = FALSE;
319
320 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
321
322 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
323 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
324 FileObject = IoStack->FileObject;
325 DPRINT("FileObject %p\n", FileObject);
326 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
327
328 Buffer = IoStack->Parameters.CreatePipe.Parameters;
329
330 Irp->IoStatus.Information = 0;
331
332 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
333 if (Fcb == NULL)
334 {
335 Irp->IoStatus.Status = STATUS_NO_MEMORY;
336 IoCompleteRequest(Irp, IO_NO_INCREMENT);
337 return STATUS_NO_MEMORY;
338 }
339
340 Fcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
341 KeLockMutex(&DeviceExt->PipeListLock);
342
343 /*
344 * First search for existing Pipe with the same name.
345 */
346 Pipe = NpfsFindPipe(DeviceExt,
347 &FileObject->FileName);
348 if (Pipe != NULL)
349 {
350 /*
351 * Found Pipe with the same name. Check if we are
352 * allowed to use it.
353 */
354 KeUnlockMutex(&DeviceExt->PipeListLock);
355
356 if (Pipe->CurrentInstances >= Pipe->MaximumInstances)
357 {
358 DPRINT("Out of instances.\n");
359 ExFreePool(Fcb);
360 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
361 IoCompleteRequest(Irp, IO_NO_INCREMENT);
362 return STATUS_PIPE_BUSY;
363 }
364
365 /* FIXME: Check pipe modes also! */
366 if (Pipe->MaximumInstances != Buffer->MaximumInstances ||
367 Pipe->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart)
368 {
369 DPRINT("Asked for invalid pipe mode.\n");
370 ExFreePool(Fcb);
371 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
372 IoCompleteRequest(Irp, IO_NO_INCREMENT);
373 return STATUS_ACCESS_DENIED;
374 }
375 }
376 else
377 {
378 NewPipe = TRUE;
379 Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
380 if (Pipe == NULL)
381 {
382 KeUnlockMutex(&DeviceExt->PipeListLock);
383 Irp->IoStatus.Status = STATUS_NO_MEMORY;
384 Irp->IoStatus.Information = 0;
385 IoCompleteRequest(Irp, IO_NO_INCREMENT);
386 return STATUS_NO_MEMORY;
387 }
388
389 Pipe->PipeName.Length = FileObject->FileName.Length;
390 Pipe->PipeName.MaximumLength = Pipe->PipeName.Length + sizeof(UNICODE_NULL);
391 Pipe->PipeName.Buffer = ExAllocatePool(NonPagedPool, Pipe->PipeName.MaximumLength);
392 if (Pipe->PipeName.Buffer == NULL)
393 {
394 KeUnlockMutex(&DeviceExt->PipeListLock);
395 ExFreePool(Pipe);
396 ExFreePool(Fcb);
397 Irp->IoStatus.Status = STATUS_NO_MEMORY;
398 Irp->IoStatus.Information = 0;
399 IoCompleteRequest(Irp, IO_NO_INCREMENT);
400 return STATUS_NO_MEMORY;
401 }
402
403 RtlCopyUnicodeString(&Pipe->PipeName, &FileObject->FileName);
404
405 InitializeListHead(&Pipe->ServerFcbListHead);
406 InitializeListHead(&Pipe->ClientFcbListHead);
407 InitializeListHead(&Pipe->WaiterListHead);
408 KeInitializeMutex(&Pipe->FcbListLock, 0);
409
410 Pipe->PipeType = Buffer->NamedPipeType;
411 Pipe->WriteMode = Buffer->ReadMode;
412 Pipe->ReadMode = Buffer->ReadMode;
413 Pipe->CompletionMode = Buffer->CompletionMode;
414 Pipe->PipeConfiguration = IoStack->Parameters.CreatePipe.Options & 0x3;
415 Pipe->MaximumInstances = Buffer->MaximumInstances;
416 Pipe->CurrentInstances = 0;
417 Pipe->TimeOut = Buffer->DefaultTimeout;
418 if (!(IoStack->Parameters.CreatePipe.Options & FILE_PIPE_OUTBOUND) ||
419 IoStack->Parameters.CreatePipe.Options & FILE_PIPE_FULL_DUPLEX)
420 {
421 if (Buffer->InboundQuota == 0)
422 {
423 Pipe->InboundQuota = DeviceExt->DefaultQuota;
424 }
425 else
426 {
427 Pipe->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
428 if (Pipe->InboundQuota < DeviceExt->MinQuota)
429 {
430 Pipe->InboundQuota = DeviceExt->MinQuota;
431 }
432 else if (Pipe->InboundQuota > DeviceExt->MaxQuota)
433 {
434 Pipe->InboundQuota = DeviceExt->MaxQuota;
435 }
436 }
437 }
438 else
439 {
440 Pipe->InboundQuota = 0;
441 }
442
443 if (IoStack->Parameters.CreatePipe.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
444 {
445 if (Buffer->OutboundQuota == 0)
446 {
447 Pipe->OutboundQuota = DeviceExt->DefaultQuota;
448 }
449 else
450 {
451 Pipe->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
452 if (Pipe->OutboundQuota < DeviceExt->MinQuota)
453 {
454 Pipe->OutboundQuota = DeviceExt->MinQuota;
455 }
456 else if (Pipe->OutboundQuota > DeviceExt->MaxQuota)
457 {
458 Pipe->OutboundQuota = DeviceExt->MaxQuota;
459 }
460 }
461 }
462 else
463 {
464 Pipe->OutboundQuota = 0;
465 }
466
467 InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
468 KeUnlockMutex(&DeviceExt->PipeListLock);
469 }
470
471 if (Pipe->InboundQuota)
472 {
473 Fcb->Data = ExAllocatePool(PagedPool, Pipe->InboundQuota);
474 if (Fcb->Data == NULL)
475 {
476 ExFreePool(Fcb);
477
478 if (NewPipe)
479 {
480 KeLockMutex(&DeviceExt->PipeListLock);
481 RemoveEntryList(&Pipe->PipeListEntry);
482 KeUnlockMutex(&DeviceExt->PipeListLock);
483 RtlFreeUnicodeString(&Pipe->PipeName);
484 ExFreePool(Pipe);
485 }
486
487 Irp->IoStatus.Status = STATUS_NO_MEMORY;
488 IoCompleteRequest(Irp, IO_NO_INCREMENT);
489 return STATUS_NO_MEMORY;
490 }
491 }
492 else
493 {
494 Fcb->Data = NULL;
495 }
496
497 Fcb->ReadPtr = Fcb->Data;
498 Fcb->WritePtr = Fcb->Data;
499 Fcb->ReadDataAvailable = 0;
500 Fcb->WriteQuotaAvailable = Pipe->InboundQuota;
501 Fcb->MaxDataLength = Pipe->InboundQuota;
502 InitializeListHead(&Fcb->ReadRequestListHead);
503 ExInitializeFastMutex(&Fcb->DataListLock);
504
505 Pipe->CurrentInstances++;
506
507 Fcb->Pipe = Pipe;
508 Fcb->PipeEnd = FILE_PIPE_SERVER_END;
509 Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
510 Fcb->OtherSide = NULL;
511
512 DPRINT("Fcb: %x\n", Fcb);
513
514 KeInitializeEvent(&Fcb->ConnectEvent, SynchronizationEvent, FALSE);
515 KeInitializeEvent(&Fcb->ReadEvent, SynchronizationEvent, FALSE);
516 KeInitializeEvent(&Fcb->WriteEvent, SynchronizationEvent, FALSE);
517
518 KeLockMutex(&Pipe->FcbListLock);
519 InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
520 KeUnlockMutex(&Pipe->FcbListLock);
521
522 FileObject->FsContext = Fcb;
523
524 Irp->IoStatus.Status = STATUS_SUCCESS;
525 IoCompleteRequest(Irp, IO_NO_INCREMENT);
526
527 DPRINT("Success!\n");
528
529 return STATUS_SUCCESS;
530 }
531
532
533 NTSTATUS STDCALL
534 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
535 PIRP Irp)
536 {
537 PNPFS_DEVICE_EXTENSION DeviceExt;
538 PIO_STACK_LOCATION IoStack;
539 PFILE_OBJECT FileObject;
540 PNPFS_FCB Fcb, OtherSide;
541 PNPFS_PIPE Pipe;
542 BOOLEAN Server;
543
544 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
545
546 IoStack = IoGetCurrentIrpStackLocation(Irp);
547 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
548 FileObject = IoStack->FileObject;
549 Fcb = FileObject->FsContext;
550
551 if (Fcb == NULL)
552 {
553 DPRINT("Success!\n");
554 Irp->IoStatus.Status = STATUS_SUCCESS;
555 Irp->IoStatus.Information = 0;
556 IoCompleteRequest(Irp, IO_NO_INCREMENT);
557 return STATUS_SUCCESS;
558 }
559
560 DPRINT("Fcb %x\n", Fcb);
561 Pipe = Fcb->Pipe;
562
563 DPRINT("Cleaning pipe %wZ\n", &Pipe->PipeName);
564
565 KeLockMutex(&Pipe->FcbListLock);
566
567 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
568
569 if (Server)
570 {
571 /* FIXME: Clean up existing connections here ?? */
572 DPRINT("Server\n");
573 }
574 else
575 {
576 DPRINT("Client\n");
577 }
578 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
579 {
580 OtherSide = Fcb->OtherSide;
581 /* Lock the server first */
582 if (Server)
583 {
584 ExAcquireFastMutex(&Fcb->DataListLock);
585 ExAcquireFastMutex(&OtherSide->DataListLock);
586 }
587 else
588 {
589 ExAcquireFastMutex(&OtherSide->DataListLock);
590 ExAcquireFastMutex(&Fcb->DataListLock);
591 }
592 OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
593 OtherSide->OtherSide = NULL;
594 /*
595 * Signaling the write event. If is possible that an other
596 * thread waits for an empty buffer.
597 */
598 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
599 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
600 if (Server)
601 {
602 ExReleaseFastMutex(&Fcb->DataListLock);
603 ExReleaseFastMutex(&OtherSide->DataListLock);
604 }
605 else
606 {
607 ExReleaseFastMutex(&OtherSide->DataListLock);
608 ExReleaseFastMutex(&Fcb->DataListLock);
609 }
610 }
611 else if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
612 {
613 PLIST_ENTRY Entry;
614 PNPFS_WAITER_ENTRY WaitEntry = NULL;
615 BOOLEAN Complete = FALSE;
616 KIRQL oldIrql;
617 PIRP tmpIrp;
618
619 Entry = Fcb->Pipe->WaiterListHead.Flink;
620 while (Entry != &Fcb->Pipe->WaiterListHead)
621 {
622 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
623 if (WaitEntry->Fcb == Fcb)
624 {
625 RemoveEntryList(Entry);
626 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
627 IoAcquireCancelSpinLock(&oldIrql);
628 if (!tmpIrp->Cancel)
629 {
630 IoSetCancelRoutine(tmpIrp, NULL);
631 Complete = TRUE;
632 }
633 IoReleaseCancelSpinLock(oldIrql);
634 if (Complete)
635 {
636 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
637 tmpIrp->IoStatus.Information = 0;
638 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
639 }
640 break;
641 }
642 Entry = Entry->Flink;
643 }
644
645 }
646 Fcb->PipeState = FILE_PIPE_CLOSING_STATE;
647
648 KeUnlockMutex(&Pipe->FcbListLock);
649
650 ExAcquireFastMutex(&Fcb->DataListLock);
651 if (Fcb->Data)
652 {
653 ExFreePool(Fcb->Data);
654 Fcb->Data = NULL;
655 Fcb->ReadPtr = NULL;
656 Fcb->WritePtr = NULL;
657 }
658 ExReleaseFastMutex(&Fcb->DataListLock);
659
660 Irp->IoStatus.Status = STATUS_SUCCESS;
661 Irp->IoStatus.Information = 0;
662 IoCompleteRequest(Irp, IO_NO_INCREMENT);
663
664 DPRINT("Success!\n");
665
666 return STATUS_SUCCESS;
667 }
668
669 NTSTATUS STDCALL
670 NpfsClose(PDEVICE_OBJECT DeviceObject,
671 PIRP Irp)
672 {
673 PNPFS_DEVICE_EXTENSION DeviceExt;
674 PIO_STACK_LOCATION IoStack;
675 PFILE_OBJECT FileObject;
676 PNPFS_FCB Fcb;
677 PNPFS_PIPE Pipe;
678 BOOLEAN Server;
679
680 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
681
682 IoStack = IoGetCurrentIrpStackLocation(Irp);
683 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
684 FileObject = IoStack->FileObject;
685 Fcb = FileObject->FsContext;
686
687 if (Fcb == NULL)
688 {
689 DPRINT("Success!\n");
690 Irp->IoStatus.Status = STATUS_SUCCESS;
691 Irp->IoStatus.Information = 0;
692 IoCompleteRequest(Irp, IO_NO_INCREMENT);
693 return STATUS_SUCCESS;
694 }
695
696 DPRINT("Fcb %x\n", Fcb);
697 Pipe = Fcb->Pipe;
698
699 DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
700
701 KeLockMutex(&Pipe->FcbListLock);
702
703 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
704
705 if (Server)
706 {
707 DPRINT("Server\n");
708 Pipe->CurrentInstances--;
709 }
710 else
711 {
712 DPRINT("Client\n");
713 }
714
715 ASSERT (Fcb->PipeState == FILE_PIPE_CLOSING_STATE);
716
717 FileObject->FsContext = NULL;
718
719 RemoveEntryList(&Fcb->FcbListEntry);
720
721 ExFreePool(Fcb);
722
723 KeUnlockMutex(&Pipe->FcbListLock);
724
725 if (IsListEmpty(&Pipe->ServerFcbListHead) &&
726 IsListEmpty(&Pipe->ClientFcbListHead))
727 {
728 RtlFreeUnicodeString(&Pipe->PipeName);
729 KeLockMutex(&DeviceExt->PipeListLock);
730 RemoveEntryList(&Pipe->PipeListEntry);
731 KeUnlockMutex(&DeviceExt->PipeListLock);
732 ExFreePool(Pipe);
733 }
734
735 Irp->IoStatus.Status = STATUS_SUCCESS;
736 Irp->IoStatus.Information = 0;
737 IoCompleteRequest(Irp, IO_NO_INCREMENT);
738
739 DPRINT("Success!\n");
740
741 return STATUS_SUCCESS;
742 }
743
744 /* EOF */