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