Merge aicom-network-branch (without NDIS changes for now)
[reactos.git] / reactos / 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, SynchronizationEvent, FALSE);
209 KeInitializeEvent(&ClientCcb->WriteEvent, SynchronizationEvent, 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 ClientCcb->Data = NULL;
259 }
260 KeUnlockMutex(&Fcb->CcbListLock);
261 Irp->IoStatus.Status = STATUS_OBJECT_PATH_NOT_FOUND;
262 IoCompleteRequest(Irp, IO_NO_INCREMENT);
263 return STATUS_OBJECT_PATH_NOT_FOUND;
264 }
265 }
266 else
267 {
268 /* Signal the server thread and remove it from the waiter list */
269 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
270 NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
271 }
272 }
273 else if (IsListEmpty(&Fcb->ServerCcbListHead))
274 {
275 DPRINT("No server fcb found!\n");
276 KeUnlockMutex(&Fcb->CcbListLock);
277 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
278 IoCompleteRequest(Irp, IO_NO_INCREMENT);
279 return STATUS_UNSUCCESSFUL;
280 }
281
282 /*
283 * Step 4. Add the client CCB to a list and connect it if possible.
284 */
285
286 /* Add the client CCB to the pipe CCB list. */
287 InsertTailList(&Fcb->ClientCcbListHead, &ClientCcb->CcbListEntry);
288
289 /* Connect to listening server side */
290 if (ServerCcb)
291 {
292 ClientCcb->OtherSide = ServerCcb;
293 ServerCcb->OtherSide = ClientCcb;
294 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
295 ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
296 KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
297 }
298
299 KeUnlockMutex(&Fcb->CcbListLock);
300
301 FileObject->FsContext = Fcb;
302 FileObject->FsContext2 = ClientCcb;
303 FileObject->Flags |= FO_NAMED_PIPE;
304
305 Irp->IoStatus.Status = STATUS_SUCCESS;
306 IoCompleteRequest(Irp, IO_NO_INCREMENT);
307
308 DPRINT("Success!\n");
309
310 return STATUS_SUCCESS;
311 }
312
313
314 NTSTATUS NTAPI
315 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
316 PIRP Irp)
317 {
318 PEXTENDED_IO_STACK_LOCATION IoStack;
319 PFILE_OBJECT FileObject;
320 PNPFS_DEVICE_EXTENSION DeviceExt;
321 PNPFS_FCB Fcb;
322 PNPFS_CCB Ccb;
323 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
324 BOOLEAN NewPipe = FALSE;
325
326 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
327
328 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
329 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
330 FileObject = IoStack->FileObject;
331 DPRINT("FileObject %p\n", FileObject);
332 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
333
334 Buffer = IoStack->Parameters.CreatePipe.Parameters;
335
336 Irp->IoStatus.Information = 0;
337
338 if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
339 (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
340 {
341 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
342 IoCompleteRequest(Irp, IO_NO_INCREMENT);
343 return STATUS_INVALID_PARAMETER;
344 }
345
346 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
347 if (Ccb == NULL)
348 {
349 Irp->IoStatus.Status = STATUS_NO_MEMORY;
350 IoCompleteRequest(Irp, IO_NO_INCREMENT);
351 return STATUS_NO_MEMORY;
352 }
353
354 Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
355 KeLockMutex(&DeviceExt->PipeListLock);
356
357 /*
358 * First search for existing Pipe with the same name.
359 */
360 Fcb = NpfsFindPipe(DeviceExt,
361 &FileObject->FileName);
362 if (Fcb != NULL)
363 {
364 /*
365 * Found Pipe with the same name. Check if we are
366 * allowed to use it.
367 */
368 KeUnlockMutex(&DeviceExt->PipeListLock);
369
370 if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
371 {
372 DPRINT("Out of instances.\n");
373 ExFreePool(Ccb);
374 Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
375 IoCompleteRequest(Irp, IO_NO_INCREMENT);
376 return STATUS_INSTANCE_NOT_AVAILABLE;
377 }
378
379 if (Fcb->MaximumInstances != Buffer->MaximumInstances ||
380 Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart ||
381 Fcb->PipeType != Buffer->NamedPipeType)
382 {
383 DPRINT("Asked for invalid pipe mode.\n");
384 ExFreePool(Ccb);
385 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
386 IoCompleteRequest(Irp, IO_NO_INCREMENT);
387 return STATUS_ACCESS_DENIED;
388 }
389 }
390 else
391 {
392 NewPipe = TRUE;
393 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
394 if (Fcb == NULL)
395 {
396 KeUnlockMutex(&DeviceExt->PipeListLock);
397 ExFreePool(Ccb);
398 Irp->IoStatus.Status = STATUS_NO_MEMORY;
399 Irp->IoStatus.Information = 0;
400 IoCompleteRequest(Irp, IO_NO_INCREMENT);
401 return STATUS_NO_MEMORY;
402 }
403
404 Fcb->PipeName.Length = FileObject->FileName.Length;
405 Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
406 Fcb->PipeName.Buffer = ExAllocatePool(NonPagedPool, Fcb->PipeName.MaximumLength);
407 if (Fcb->PipeName.Buffer == NULL)
408 {
409 KeUnlockMutex(&DeviceExt->PipeListLock);
410 ExFreePool(Fcb);
411 ExFreePool(Ccb);
412 Irp->IoStatus.Status = STATUS_NO_MEMORY;
413 Irp->IoStatus.Information = 0;
414 IoCompleteRequest(Irp, IO_NO_INCREMENT);
415 return STATUS_NO_MEMORY;
416 }
417
418 RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName);
419
420 InitializeListHead(&Fcb->ServerCcbListHead);
421 InitializeListHead(&Fcb->ClientCcbListHead);
422 InitializeListHead(&Fcb->WaiterListHead);
423 KeInitializeMutex(&Fcb->CcbListLock, 0);
424
425 Fcb->PipeType = Buffer->NamedPipeType;
426 Fcb->ServerReadMode = Buffer->ReadMode;
427 /* MSDN documentation reads that clients always start off in byte mode */
428 Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE;
429
430 Fcb->CompletionMode = Buffer->CompletionMode;
431 switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
432 {
433 case FILE_SHARE_READ:
434 Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND;
435 break;
436 case FILE_SHARE_WRITE:
437 Fcb->PipeConfiguration = FILE_PIPE_INBOUND;
438 break;
439 case FILE_SHARE_READ|FILE_SHARE_WRITE:
440 Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
441 break;
442 }
443 Fcb->MaximumInstances = Buffer->MaximumInstances;
444 Fcb->CurrentInstances = 0;
445 Fcb->TimeOut = Buffer->DefaultTimeout;
446 if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
447 Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
448 {
449 if (Buffer->InboundQuota == 0)
450 {
451 Fcb->InboundQuota = DeviceExt->DefaultQuota;
452 }
453 else
454 {
455 Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
456 if (Fcb->InboundQuota < DeviceExt->MinQuota)
457 {
458 Fcb->InboundQuota = DeviceExt->MinQuota;
459 }
460 else if (Fcb->InboundQuota > DeviceExt->MaxQuota)
461 {
462 Fcb->InboundQuota = DeviceExt->MaxQuota;
463 }
464 }
465 }
466 else
467 {
468 Fcb->InboundQuota = 0;
469 }
470
471 if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
472 {
473 if (Buffer->OutboundQuota == 0)
474 {
475 Fcb->OutboundQuota = DeviceExt->DefaultQuota;
476 }
477 else
478 {
479 Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
480 if (Fcb->OutboundQuota < DeviceExt->MinQuota)
481 {
482 Fcb->OutboundQuota = DeviceExt->MinQuota;
483 }
484 else if (Fcb->OutboundQuota > DeviceExt->MaxQuota)
485 {
486 Fcb->OutboundQuota = DeviceExt->MaxQuota;
487 }
488 }
489 }
490 else
491 {
492 Fcb->OutboundQuota = 0;
493 }
494
495 InsertTailList(&DeviceExt->PipeListHead, &Fcb->PipeListEntry);
496 KeUnlockMutex(&DeviceExt->PipeListLock);
497 }
498
499 if (Fcb->InboundQuota)
500 {
501 Ccb->Data = ExAllocatePool(PagedPool, Fcb->InboundQuota);
502 if (Ccb->Data == NULL)
503 {
504 ExFreePool(Ccb);
505
506 if (NewPipe)
507 {
508 KeLockMutex(&DeviceExt->PipeListLock);
509 RemoveEntryList(&Fcb->PipeListEntry);
510 KeUnlockMutex(&DeviceExt->PipeListLock);
511 RtlFreeUnicodeString(&Fcb->PipeName);
512 ExFreePool(Fcb);
513 }
514
515 Irp->IoStatus.Status = STATUS_NO_MEMORY;
516 IoCompleteRequest(Irp, IO_NO_INCREMENT);
517 return STATUS_NO_MEMORY;
518 }
519 }
520 else
521 {
522 Ccb->Data = NULL;
523 }
524
525 Ccb->ReadPtr = Ccb->Data;
526 Ccb->WritePtr = Ccb->Data;
527 Ccb->ReadDataAvailable = 0;
528 Ccb->WriteQuotaAvailable = Fcb->InboundQuota;
529 Ccb->MaxDataLength = Fcb->InboundQuota;
530 InitializeListHead(&Ccb->ReadRequestListHead);
531 ExInitializeFastMutex(&Ccb->DataListLock);
532
533 Fcb->CurrentInstances++;
534
535 Ccb->Fcb = Fcb;
536 Ccb->PipeEnd = FILE_PIPE_SERVER_END;
537 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
538 Ccb->OtherSide = NULL;
539
540 DPRINT("CCB: %p\n", Ccb);
541
542 KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE);
543 KeInitializeEvent(&Ccb->ReadEvent, SynchronizationEvent, FALSE);
544 KeInitializeEvent(&Ccb->WriteEvent, SynchronizationEvent, FALSE);
545
546 KeLockMutex(&Fcb->CcbListLock);
547 InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry);
548 KeUnlockMutex(&Fcb->CcbListLock);
549
550 FileObject->FsContext = Fcb;
551 FileObject->FsContext2 = Ccb;
552 FileObject->Flags |= FO_NAMED_PIPE;
553
554 Irp->IoStatus.Status = STATUS_SUCCESS;
555 IoCompleteRequest(Irp, IO_NO_INCREMENT);
556
557 DPRINT("Success!\n");
558
559 return STATUS_SUCCESS;
560 }
561
562
563 NTSTATUS NTAPI
564 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
565 PIRP Irp)
566 {
567 PNPFS_DEVICE_EXTENSION DeviceExt;
568 PIO_STACK_LOCATION IoStack;
569 PFILE_OBJECT FileObject;
570 PNPFS_CCB Ccb, OtherSide;
571 PNPFS_FCB Fcb;
572 BOOLEAN Server;
573
574 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
575
576 IoStack = IoGetCurrentIrpStackLocation(Irp);
577 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
578 FileObject = IoStack->FileObject;
579 Ccb = FileObject->FsContext2;
580
581 if (Ccb == NULL)
582 {
583 DPRINT("Success!\n");
584 Irp->IoStatus.Status = STATUS_SUCCESS;
585 Irp->IoStatus.Information = 0;
586 IoCompleteRequest(Irp, IO_NO_INCREMENT);
587 return STATUS_SUCCESS;
588 }
589
590 DPRINT("CCB %p\n", Ccb);
591 Fcb = Ccb->Fcb;
592
593 DPRINT("Cleaning pipe %wZ\n", &Fcb->PipeName);
594
595 KeLockMutex(&Fcb->CcbListLock);
596
597 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
598
599 if (Server)
600 {
601 /* FIXME: Clean up existing connections here ?? */
602 DPRINT("Server\n");
603 }
604 else
605 {
606 DPRINT("Client\n");
607 }
608 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
609 {
610 OtherSide = Ccb->OtherSide;
611 /* Lock the server first */
612 if (Server)
613 {
614 ExAcquireFastMutex(&Ccb->DataListLock);
615 ExAcquireFastMutex(&OtherSide->DataListLock);
616 }
617 else
618 {
619 ExAcquireFastMutex(&OtherSide->DataListLock);
620 ExAcquireFastMutex(&Ccb->DataListLock);
621 }
622 //OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
623 OtherSide->OtherSide = NULL;
624 /*
625 * Signaling the write event. If is possible that an other
626 * thread waits for an empty buffer.
627 */
628 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
629 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
630 if (Server)
631 {
632 ExReleaseFastMutex(&OtherSide->DataListLock);
633 ExReleaseFastMutex(&Ccb->DataListLock);
634 }
635 else
636 {
637 ExReleaseFastMutex(&Ccb->DataListLock);
638 ExReleaseFastMutex(&OtherSide->DataListLock);
639 }
640 }
641 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
642 {
643 PLIST_ENTRY Entry;
644 PNPFS_WAITER_ENTRY WaitEntry = NULL;
645 BOOLEAN Complete = FALSE;
646 KIRQL oldIrql;
647 PIRP tmpIrp;
648
649 Entry = Ccb->Fcb->WaiterListHead.Flink;
650 while (Entry != &Ccb->Fcb->WaiterListHead)
651 {
652 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
653 if (WaitEntry->Ccb == Ccb)
654 {
655 RemoveEntryList(Entry);
656 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
657 IoAcquireCancelSpinLock(&oldIrql);
658 if (!tmpIrp->Cancel)
659 {
660 (void)IoSetCancelRoutine(tmpIrp, NULL);
661 Complete = TRUE;
662 }
663 IoReleaseCancelSpinLock(oldIrql);
664 if (Complete)
665 {
666 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
667 tmpIrp->IoStatus.Information = 0;
668 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
669 }
670 break;
671 }
672 Entry = Entry->Flink;
673 }
674
675 }
676 Ccb->PipeState = FILE_PIPE_CLOSING_STATE;
677
678 KeUnlockMutex(&Fcb->CcbListLock);
679
680 ExAcquireFastMutex(&Ccb->DataListLock);
681 if (Ccb->Data)
682 {
683 ExFreePool(Ccb->Data);
684 Ccb->Data = NULL;
685 Ccb->ReadPtr = NULL;
686 Ccb->WritePtr = NULL;
687 }
688 ExReleaseFastMutex(&Ccb->DataListLock);
689
690 Irp->IoStatus.Status = STATUS_SUCCESS;
691 Irp->IoStatus.Information = 0;
692 IoCompleteRequest(Irp, IO_NO_INCREMENT);
693
694 DPRINT("Success!\n");
695
696 return STATUS_SUCCESS;
697 }
698
699 NTSTATUS NTAPI
700 NpfsClose(PDEVICE_OBJECT DeviceObject,
701 PIRP Irp)
702 {
703 PNPFS_DEVICE_EXTENSION DeviceExt;
704 PIO_STACK_LOCATION IoStack;
705 PFILE_OBJECT FileObject;
706 PNPFS_FCB Fcb;
707 PNPFS_CCB Ccb;
708 BOOLEAN Server;
709
710 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
711
712 IoStack = IoGetCurrentIrpStackLocation(Irp);
713 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
714 FileObject = IoStack->FileObject;
715 Ccb = FileObject->FsContext2;
716
717 if (Ccb == NULL)
718 {
719 DPRINT("Success!\n");
720 Irp->IoStatus.Status = STATUS_SUCCESS;
721 Irp->IoStatus.Information = 0;
722 IoCompleteRequest(Irp, IO_NO_INCREMENT);
723 return STATUS_SUCCESS;
724 }
725
726 DPRINT("CCB %p\n", Ccb);
727 Fcb = Ccb->Fcb;
728
729 DPRINT("Closing pipe %wZ\n", &Fcb->PipeName);
730
731 KeLockMutex(&Fcb->CcbListLock);
732
733 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
734
735 if (Server)
736 {
737 DPRINT("Server\n");
738 Fcb->CurrentInstances--;
739 }
740 else
741 {
742 DPRINT("Client\n");
743 }
744
745 /* Disconnect the pipes */
746 if (Ccb->OtherSide) Ccb->OtherSide->OtherSide = NULL;
747 if (Ccb) Ccb->OtherSide = NULL;
748
749 ASSERT(Ccb->PipeState == FILE_PIPE_CLOSING_STATE);
750
751 FileObject->FsContext2 = NULL;
752
753 RemoveEntryList(&Ccb->CcbListEntry);
754
755 ExFreePool(Ccb);
756
757 KeUnlockMutex(&Fcb->CcbListLock);
758
759 if (IsListEmpty(&Fcb->ServerCcbListHead) &&
760 IsListEmpty(&Fcb->ClientCcbListHead))
761 {
762 RtlFreeUnicodeString(&Fcb->PipeName);
763 KeLockMutex(&DeviceExt->PipeListLock);
764 RemoveEntryList(&Fcb->PipeListEntry);
765 KeUnlockMutex(&DeviceExt->PipeListLock);
766 ExFreePool(Fcb);
767 FileObject->FsContext = NULL;
768 }
769
770 Irp->IoStatus.Status = STATUS_SUCCESS;
771 Irp->IoStatus.Information = 0;
772 IoCompleteRequest(Irp, IO_NO_INCREMENT);
773
774 DPRINT("Success!\n");
775
776 return STATUS_SUCCESS;
777 }
778
779 /* EOF */