It is generally considered a good idea to release a fast mutex in the same order...
[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 if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
333 (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
334 {
335 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
336 IoCompleteRequest(Irp, IO_NO_INCREMENT);
337 return STATUS_INVALID_PARAMETER;
338 }
339
340 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
341 if (Fcb == NULL)
342 {
343 Irp->IoStatus.Status = STATUS_NO_MEMORY;
344 IoCompleteRequest(Irp, IO_NO_INCREMENT);
345 return STATUS_NO_MEMORY;
346 }
347
348 Fcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
349 KeLockMutex(&DeviceExt->PipeListLock);
350
351 /*
352 * First search for existing Pipe with the same name.
353 */
354 Pipe = NpfsFindPipe(DeviceExt,
355 &FileObject->FileName);
356 if (Pipe != NULL)
357 {
358 /*
359 * Found Pipe with the same name. Check if we are
360 * allowed to use it.
361 */
362 KeUnlockMutex(&DeviceExt->PipeListLock);
363
364 if (Pipe->CurrentInstances >= Pipe->MaximumInstances)
365 {
366 DPRINT("Out of instances.\n");
367 ExFreePool(Fcb);
368 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
369 IoCompleteRequest(Irp, IO_NO_INCREMENT);
370 return STATUS_PIPE_BUSY;
371 }
372
373 /* FIXME: Check pipe modes also! */
374 if (Pipe->MaximumInstances != Buffer->MaximumInstances ||
375 Pipe->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart)
376 {
377 DPRINT("Asked for invalid pipe mode.\n");
378 ExFreePool(Fcb);
379 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
380 IoCompleteRequest(Irp, IO_NO_INCREMENT);
381 return STATUS_ACCESS_DENIED;
382 }
383 }
384 else
385 {
386 NewPipe = TRUE;
387 Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
388 if (Pipe == NULL)
389 {
390 KeUnlockMutex(&DeviceExt->PipeListLock);
391 Irp->IoStatus.Status = STATUS_NO_MEMORY;
392 Irp->IoStatus.Information = 0;
393 IoCompleteRequest(Irp, IO_NO_INCREMENT);
394 return STATUS_NO_MEMORY;
395 }
396
397 Pipe->PipeName.Length = FileObject->FileName.Length;
398 Pipe->PipeName.MaximumLength = Pipe->PipeName.Length + sizeof(UNICODE_NULL);
399 Pipe->PipeName.Buffer = ExAllocatePool(NonPagedPool, Pipe->PipeName.MaximumLength);
400 if (Pipe->PipeName.Buffer == NULL)
401 {
402 KeUnlockMutex(&DeviceExt->PipeListLock);
403 ExFreePool(Pipe);
404 ExFreePool(Fcb);
405 Irp->IoStatus.Status = STATUS_NO_MEMORY;
406 Irp->IoStatus.Information = 0;
407 IoCompleteRequest(Irp, IO_NO_INCREMENT);
408 return STATUS_NO_MEMORY;
409 }
410
411 RtlCopyUnicodeString(&Pipe->PipeName, &FileObject->FileName);
412
413 InitializeListHead(&Pipe->ServerFcbListHead);
414 InitializeListHead(&Pipe->ClientFcbListHead);
415 InitializeListHead(&Pipe->WaiterListHead);
416 KeInitializeMutex(&Pipe->FcbListLock, 0);
417
418 Pipe->PipeType = Buffer->NamedPipeType;
419 Pipe->WriteMode = Buffer->ReadMode;
420 Pipe->ReadMode = Buffer->ReadMode;
421 Pipe->CompletionMode = Buffer->CompletionMode;
422 switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
423 {
424 case FILE_SHARE_READ:
425 Pipe->PipeConfiguration = FILE_PIPE_OUTBOUND;
426 break;
427 case FILE_SHARE_WRITE:
428 Pipe->PipeConfiguration = FILE_PIPE_INBOUND;
429 break;
430 case FILE_SHARE_READ|FILE_SHARE_WRITE:
431 Pipe->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
432 break;
433 }
434 Pipe->MaximumInstances = Buffer->MaximumInstances;
435 Pipe->CurrentInstances = 0;
436 Pipe->TimeOut = Buffer->DefaultTimeout;
437 if (!(Pipe->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
438 Pipe->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
439 {
440 if (Buffer->InboundQuota == 0)
441 {
442 Pipe->InboundQuota = DeviceExt->DefaultQuota;
443 }
444 else
445 {
446 Pipe->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
447 if (Pipe->InboundQuota < DeviceExt->MinQuota)
448 {
449 Pipe->InboundQuota = DeviceExt->MinQuota;
450 }
451 else if (Pipe->InboundQuota > DeviceExt->MaxQuota)
452 {
453 Pipe->InboundQuota = DeviceExt->MaxQuota;
454 }
455 }
456 }
457 else
458 {
459 Pipe->InboundQuota = 0;
460 }
461
462 if (Pipe->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
463 {
464 if (Buffer->OutboundQuota == 0)
465 {
466 Pipe->OutboundQuota = DeviceExt->DefaultQuota;
467 }
468 else
469 {
470 Pipe->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
471 if (Pipe->OutboundQuota < DeviceExt->MinQuota)
472 {
473 Pipe->OutboundQuota = DeviceExt->MinQuota;
474 }
475 else if (Pipe->OutboundQuota > DeviceExt->MaxQuota)
476 {
477 Pipe->OutboundQuota = DeviceExt->MaxQuota;
478 }
479 }
480 }
481 else
482 {
483 Pipe->OutboundQuota = 0;
484 }
485
486 InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
487 KeUnlockMutex(&DeviceExt->PipeListLock);
488 }
489
490 if (Pipe->InboundQuota)
491 {
492 Fcb->Data = ExAllocatePool(PagedPool, Pipe->InboundQuota);
493 if (Fcb->Data == NULL)
494 {
495 ExFreePool(Fcb);
496
497 if (NewPipe)
498 {
499 KeLockMutex(&DeviceExt->PipeListLock);
500 RemoveEntryList(&Pipe->PipeListEntry);
501 KeUnlockMutex(&DeviceExt->PipeListLock);
502 RtlFreeUnicodeString(&Pipe->PipeName);
503 ExFreePool(Pipe);
504 }
505
506 Irp->IoStatus.Status = STATUS_NO_MEMORY;
507 IoCompleteRequest(Irp, IO_NO_INCREMENT);
508 return STATUS_NO_MEMORY;
509 }
510 }
511 else
512 {
513 Fcb->Data = NULL;
514 }
515
516 Fcb->ReadPtr = Fcb->Data;
517 Fcb->WritePtr = Fcb->Data;
518 Fcb->ReadDataAvailable = 0;
519 Fcb->WriteQuotaAvailable = Pipe->InboundQuota;
520 Fcb->MaxDataLength = Pipe->InboundQuota;
521 InitializeListHead(&Fcb->ReadRequestListHead);
522 ExInitializeFastMutex(&Fcb->DataListLock);
523
524 Pipe->CurrentInstances++;
525
526 Fcb->Pipe = Pipe;
527 Fcb->PipeEnd = FILE_PIPE_SERVER_END;
528 Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
529 Fcb->OtherSide = NULL;
530
531 DPRINT("Fcb: %x\n", Fcb);
532
533 KeInitializeEvent(&Fcb->ConnectEvent, SynchronizationEvent, FALSE);
534 KeInitializeEvent(&Fcb->ReadEvent, SynchronizationEvent, FALSE);
535 KeInitializeEvent(&Fcb->WriteEvent, SynchronizationEvent, FALSE);
536
537 KeLockMutex(&Pipe->FcbListLock);
538 InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
539 KeUnlockMutex(&Pipe->FcbListLock);
540
541 FileObject->FsContext = Fcb;
542
543 Irp->IoStatus.Status = STATUS_SUCCESS;
544 IoCompleteRequest(Irp, IO_NO_INCREMENT);
545
546 DPRINT("Success!\n");
547
548 return STATUS_SUCCESS;
549 }
550
551
552 NTSTATUS STDCALL
553 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
554 PIRP Irp)
555 {
556 PNPFS_DEVICE_EXTENSION DeviceExt;
557 PIO_STACK_LOCATION IoStack;
558 PFILE_OBJECT FileObject;
559 PNPFS_FCB Fcb, OtherSide;
560 PNPFS_PIPE Pipe;
561 BOOLEAN Server;
562
563 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
564
565 IoStack = IoGetCurrentIrpStackLocation(Irp);
566 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
567 FileObject = IoStack->FileObject;
568 Fcb = FileObject->FsContext;
569
570 if (Fcb == NULL)
571 {
572 DPRINT("Success!\n");
573 Irp->IoStatus.Status = STATUS_SUCCESS;
574 Irp->IoStatus.Information = 0;
575 IoCompleteRequest(Irp, IO_NO_INCREMENT);
576 return STATUS_SUCCESS;
577 }
578
579 DPRINT("Fcb %x\n", Fcb);
580 Pipe = Fcb->Pipe;
581
582 DPRINT("Cleaning pipe %wZ\n", &Pipe->PipeName);
583
584 KeLockMutex(&Pipe->FcbListLock);
585
586 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
587
588 if (Server)
589 {
590 /* FIXME: Clean up existing connections here ?? */
591 DPRINT("Server\n");
592 }
593 else
594 {
595 DPRINT("Client\n");
596 }
597 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
598 {
599 OtherSide = Fcb->OtherSide;
600 /* Lock the server first */
601 if (Server)
602 {
603 ExAcquireFastMutex(&Fcb->DataListLock);
604 ExAcquireFastMutex(&OtherSide->DataListLock);
605 }
606 else
607 {
608 ExAcquireFastMutex(&OtherSide->DataListLock);
609 ExAcquireFastMutex(&Fcb->DataListLock);
610 }
611 OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
612 OtherSide->OtherSide = NULL;
613 /*
614 * Signaling the write event. If is possible that an other
615 * thread waits for an empty buffer.
616 */
617 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
618 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
619 if (Server)
620 {
621 ExReleaseFastMutex(&OtherSide->DataListLock);
622 ExReleaseFastMutex(&Fcb->DataListLock);
623 }
624 else
625 {
626 ExReleaseFastMutex(&Fcb->DataListLock);
627 ExReleaseFastMutex(&OtherSide->DataListLock);
628 }
629 }
630 else if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
631 {
632 PLIST_ENTRY Entry;
633 PNPFS_WAITER_ENTRY WaitEntry = NULL;
634 BOOLEAN Complete = FALSE;
635 KIRQL oldIrql;
636 PIRP tmpIrp;
637
638 Entry = Fcb->Pipe->WaiterListHead.Flink;
639 while (Entry != &Fcb->Pipe->WaiterListHead)
640 {
641 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
642 if (WaitEntry->Fcb == Fcb)
643 {
644 RemoveEntryList(Entry);
645 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
646 IoAcquireCancelSpinLock(&oldIrql);
647 if (!tmpIrp->Cancel)
648 {
649 IoSetCancelRoutine(tmpIrp, NULL);
650 Complete = TRUE;
651 }
652 IoReleaseCancelSpinLock(oldIrql);
653 if (Complete)
654 {
655 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
656 tmpIrp->IoStatus.Information = 0;
657 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
658 }
659 break;
660 }
661 Entry = Entry->Flink;
662 }
663
664 }
665 Fcb->PipeState = FILE_PIPE_CLOSING_STATE;
666
667 KeUnlockMutex(&Pipe->FcbListLock);
668
669 ExAcquireFastMutex(&Fcb->DataListLock);
670 if (Fcb->Data)
671 {
672 ExFreePool(Fcb->Data);
673 Fcb->Data = NULL;
674 Fcb->ReadPtr = NULL;
675 Fcb->WritePtr = NULL;
676 }
677 ExReleaseFastMutex(&Fcb->DataListLock);
678
679 Irp->IoStatus.Status = STATUS_SUCCESS;
680 Irp->IoStatus.Information = 0;
681 IoCompleteRequest(Irp, IO_NO_INCREMENT);
682
683 DPRINT("Success!\n");
684
685 return STATUS_SUCCESS;
686 }
687
688 NTSTATUS STDCALL
689 NpfsClose(PDEVICE_OBJECT DeviceObject,
690 PIRP Irp)
691 {
692 PNPFS_DEVICE_EXTENSION DeviceExt;
693 PIO_STACK_LOCATION IoStack;
694 PFILE_OBJECT FileObject;
695 PNPFS_FCB Fcb;
696 PNPFS_PIPE Pipe;
697 BOOLEAN Server;
698
699 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
700
701 IoStack = IoGetCurrentIrpStackLocation(Irp);
702 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
703 FileObject = IoStack->FileObject;
704 Fcb = FileObject->FsContext;
705
706 if (Fcb == NULL)
707 {
708 DPRINT("Success!\n");
709 Irp->IoStatus.Status = STATUS_SUCCESS;
710 Irp->IoStatus.Information = 0;
711 IoCompleteRequest(Irp, IO_NO_INCREMENT);
712 return STATUS_SUCCESS;
713 }
714
715 DPRINT("Fcb %x\n", Fcb);
716 Pipe = Fcb->Pipe;
717
718 DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
719
720 KeLockMutex(&Pipe->FcbListLock);
721
722 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
723
724 if (Server)
725 {
726 DPRINT("Server\n");
727 Pipe->CurrentInstances--;
728 }
729 else
730 {
731 DPRINT("Client\n");
732 }
733
734 ASSERT (Fcb->PipeState == FILE_PIPE_CLOSING_STATE);
735
736 FileObject->FsContext = NULL;
737
738 RemoveEntryList(&Fcb->FcbListEntry);
739
740 ExFreePool(Fcb);
741
742 KeUnlockMutex(&Pipe->FcbListLock);
743
744 if (IsListEmpty(&Pipe->ServerFcbListHead) &&
745 IsListEmpty(&Pipe->ClientFcbListHead))
746 {
747 RtlFreeUnicodeString(&Pipe->PipeName);
748 KeLockMutex(&DeviceExt->PipeListLock);
749 RemoveEntryList(&Pipe->PipeListEntry);
750 KeUnlockMutex(&DeviceExt->PipeListLock);
751 ExFreePool(Pipe);
752 }
753
754 Irp->IoStatus.Status = STATUS_SUCCESS;
755 Irp->IoStatus.Information = 0;
756 IoCompleteRequest(Irp, IO_NO_INCREMENT);
757
758 DPRINT("Success!\n");
759
760 return STATUS_SUCCESS;
761 }
762
763 /* EOF */