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