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