[CMAKE]
[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 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
17
18 /* FUNCTIONS *****************************************************************/
19
20 PNPFS_FCB
21 NpfsFindPipe(PNPFS_VCB Vcb,
22 PUNICODE_STRING PipeName)
23 {
24 PLIST_ENTRY CurrentEntry;
25 PNPFS_FCB Fcb;
26
27 CurrentEntry = Vcb->PipeListHead.Flink;
28 while (CurrentEntry != &Vcb->PipeListHead)
29 {
30 Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, PipeListEntry);
31 if (RtlCompareUnicodeString(PipeName,
32 &Fcb->PipeName,
33 TRUE) == 0)
34 {
35 DPRINT("<%wZ> = <%wZ>\n", PipeName, &Fcb->PipeName);
36 return Fcb;
37 }
38
39 CurrentEntry = CurrentEntry->Flink;
40 }
41
42 return NULL;
43 }
44
45
46 static PNPFS_CCB
47 NpfsFindListeningServerInstance(PNPFS_FCB Fcb)
48 {
49 PLIST_ENTRY CurrentEntry;
50 PNPFS_WAITER_ENTRY Waiter;
51 KIRQL oldIrql;
52 PIRP Irp;
53
54 CurrentEntry = Fcb->WaiterListHead.Flink;
55 while (CurrentEntry != &Fcb->WaiterListHead)
56 {
57 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
58 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
59 if (Waiter->Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
60 {
61 DPRINT("Server found! CCB %p\n", Waiter->Ccb);
62
63 IoAcquireCancelSpinLock(&oldIrql);
64 if (!Irp->Cancel)
65 {
66 (void)IoSetCancelRoutine(Irp, NULL);
67 IoReleaseCancelSpinLock(oldIrql);
68 return Waiter->Ccb;
69 }
70 IoReleaseCancelSpinLock(oldIrql);
71 }
72
73 CurrentEntry = CurrentEntry->Flink;
74 }
75
76 return NULL;
77 }
78
79
80 static VOID
81 NpfsSignalAndRemoveListeningServerInstance(PNPFS_FCB Fcb,
82 PNPFS_CCB Ccb)
83 {
84 PLIST_ENTRY CurrentEntry;
85 PNPFS_WAITER_ENTRY Waiter;
86 PIRP Irp;
87
88 CurrentEntry = Fcb->WaiterListHead.Flink;
89 while (CurrentEntry != &Fcb->WaiterListHead)
90 {
91 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
92 if (Waiter->Ccb == Ccb)
93 {
94 DPRINT("Server found! CCB %p\n", Waiter->Ccb);
95
96 RemoveEntryList(&Waiter->Entry);
97 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
98 Irp->IoStatus.Status = STATUS_SUCCESS;
99 Irp->IoStatus.Information = 0;
100 IoCompleteRequest(Irp, IO_NO_INCREMENT);
101 break;
102 }
103 CurrentEntry = CurrentEntry->Flink;
104 }
105 }
106
107
108 static VOID
109 NpfsOpenFileSystem(PNPFS_FCB Fcb,
110 PFILE_OBJECT FileObject,
111 PIO_STATUS_BLOCK IoStatus)
112 {
113 PNPFS_CCB Ccb;
114
115 DPRINT("NpfsOpenFileSystem()\n");
116
117 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
118 if (Ccb == NULL)
119 {
120 IoStatus->Status = STATUS_NO_MEMORY;
121 return;
122 }
123
124 RtlZeroMemory(Ccb, sizeof(NPFS_CCB));
125
126 Ccb->Type = CCB_DEVICE;
127 Ccb->Fcb = Fcb;
128
129 FileObject->FsContext = Fcb;
130 FileObject->FsContext2 = Ccb;
131
132 IoStatus->Information = FILE_OPENED;
133 IoStatus->Status = STATUS_SUCCESS;
134
135 return;
136 }
137
138
139 static VOID
140 NpfsOpenRootDirectory(PNPFS_FCB Fcb,
141 PFILE_OBJECT FileObject,
142 PIO_STATUS_BLOCK IoStatus)
143 {
144 PNPFS_CCB Ccb;
145
146 DPRINT("NpfsOpenRootDirectory()\n");
147
148 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
149 if (Ccb == NULL)
150 {
151 IoStatus->Status = STATUS_NO_MEMORY;
152 return;
153 }
154
155 RtlZeroMemory(Ccb, sizeof(NPFS_CCB));
156
157 Ccb->Type = CCB_DIRECTORY;
158 Ccb->Fcb = Fcb;
159
160 FileObject->FsContext = Fcb;
161 FileObject->FsContext2 = Ccb;
162
163 IoStatus->Information = FILE_OPENED;
164 IoStatus->Status = STATUS_SUCCESS;
165
166 return;
167 }
168
169
170 NTSTATUS NTAPI
171 NpfsCreate(PDEVICE_OBJECT DeviceObject,
172 PIRP Irp)
173 {
174 PEXTENDED_IO_STACK_LOCATION IoStack;
175 PUNICODE_STRING FileName;
176 PFILE_OBJECT FileObject;
177 PFILE_OBJECT RelatedFileObject;
178 PNPFS_FCB Fcb;
179 PNPFS_CCB ClientCcb;
180 PNPFS_CCB ServerCcb = NULL;
181 PNPFS_VCB Vcb;
182 ACCESS_MASK DesiredAccess;
183 NTSTATUS Status;
184 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
185 BOOLEAN SpecialAccess;
186 #endif
187
188 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
189
190 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
191 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
192 FileObject = IoStack->FileObject;
193 RelatedFileObject = FileObject->RelatedFileObject;
194 FileName = &FileObject->FileName;
195 DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
196
197 DPRINT("FileObject %p\n", FileObject);
198 DPRINT("FileName %wZ\n", &FileObject->FileName);
199
200 Irp->IoStatus.Information = 0;
201
202 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
203 SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES);
204 if (SpecialAccess)
205 {
206 DPRINT("NpfsCreate() open client end for special use!\n");
207 }
208 #endif
209
210 DPRINT("FileName->Length: %hu RelatedFileObject: %p\n", FileName->Length, RelatedFileObject);
211
212 /* Open the file system */
213 if (FileName->Length == 0 &&
214 (RelatedFileObject == NULL || ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DEVICE))
215 {
216 DPRINT("Open the file system\n");
217
218 NpfsOpenFileSystem(Vcb->DeviceFcb,
219 FileObject,
220 &Irp->IoStatus);
221
222 Status = Irp->IoStatus.Status;
223 IoCompleteRequest(Irp, IO_NO_INCREMENT);
224 return Status;
225 }
226
227 /* Open the root directory */
228 if ((FileName->Length == 2 && FileName->Buffer[0] == L'\\' && RelatedFileObject == NULL) ||
229 (FileName->Length == 0 && ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DIRECTORY))
230 {
231 DPRINT("Open the root directory\n");
232
233 NpfsOpenRootDirectory(Vcb->RootFcb,
234 FileObject,
235 &Irp->IoStatus);
236
237 Status = Irp->IoStatus.Status;
238 IoCompleteRequest(Irp, IO_NO_INCREMENT);
239 return Status;
240 }
241
242
243 /*
244 * Step 1. Find the pipe we're trying to open.
245 */
246 KeLockMutex(&Vcb->PipeListLock);
247 Fcb = NpfsFindPipe(Vcb,
248 &FileObject->FileName);
249 if (Fcb == NULL)
250 {
251 /* Not found, bail out with error. */
252 DPRINT("No pipe found!\n");
253 KeUnlockMutex(&Vcb->PipeListLock);
254 Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
255 IoCompleteRequest(Irp, IO_NO_INCREMENT);
256 return STATUS_OBJECT_NAME_NOT_FOUND;
257 }
258
259 KeUnlockMutex(&Vcb->PipeListLock);
260
261 /*
262 * Acquire the lock for CCB lists. From now on no modifications to the
263 * CCB lists are allowed, because it can cause various misconsistencies.
264 */
265 KeLockMutex(&Fcb->CcbListLock);
266
267 /*
268 * Step 2. Create the client CCB.
269 */
270 ClientCcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
271 if (ClientCcb == NULL)
272 {
273 DPRINT("No memory!\n");
274 KeUnlockMutex(&Fcb->CcbListLock);
275 Irp->IoStatus.Status = STATUS_NO_MEMORY;
276 IoCompleteRequest(Irp, IO_NO_INCREMENT);
277 return STATUS_NO_MEMORY;
278 }
279
280 ClientCcb->Type = CCB_PIPE;
281 ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
282 ClientCcb->Fcb = Fcb;
283 ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END;
284 ClientCcb->OtherSide = NULL;
285 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
286 ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
287 #else
288 ClientCcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
289 #endif
290 InitializeListHead(&ClientCcb->ReadRequestListHead);
291
292 DPRINT("CCB: %p\n", ClientCcb);
293
294 /* Initialize data list. */
295 if (Fcb->OutboundQuota)
296 {
297 ClientCcb->Data = ExAllocatePool(PagedPool, Fcb->OutboundQuota);
298 if (ClientCcb->Data == NULL)
299 {
300 DPRINT("No memory!\n");
301 ExFreePool(ClientCcb);
302 KeUnlockMutex(&Fcb->CcbListLock);
303 Irp->IoStatus.Status = STATUS_NO_MEMORY;
304 IoCompleteRequest(Irp, IO_NO_INCREMENT);
305 return STATUS_NO_MEMORY;
306 }
307 }
308 else
309 {
310 ClientCcb->Data = NULL;
311 }
312
313 ClientCcb->ReadPtr = ClientCcb->Data;
314 ClientCcb->WritePtr = ClientCcb->Data;
315 ClientCcb->ReadDataAvailable = 0;
316 ClientCcb->WriteQuotaAvailable = Fcb->OutboundQuota;
317 ClientCcb->MaxDataLength = Fcb->OutboundQuota;
318 ExInitializeFastMutex(&ClientCcb->DataListLock);
319 KeInitializeEvent(&ClientCcb->ConnectEvent, SynchronizationEvent, FALSE);
320 KeInitializeEvent(&ClientCcb->ReadEvent, NotificationEvent, FALSE);
321 KeInitializeEvent(&ClientCcb->WriteEvent, NotificationEvent, FALSE);
322
323
324 /*
325 * Step 3. Search for listening server CCB.
326 */
327 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
328 if (!SpecialAccess)
329 {
330 #endif
331 /*
332 * WARNING: Point of no return! Once we get the server CCB it's
333 * possible that we completed a wait request and so we have to
334 * complete even this request.
335 */
336
337 ServerCcb = NpfsFindListeningServerInstance(Fcb);
338 if (ServerCcb == NULL)
339 {
340 PLIST_ENTRY CurrentEntry;
341 PNPFS_CCB Ccb;
342
343 /*
344 * If no waiting server CCB was found then try to pick
345 * one of the listing server CCB on the pipe.
346 */
347
348 CurrentEntry = Fcb->ServerCcbListHead.Flink;
349 while (CurrentEntry != &Fcb->ServerCcbListHead)
350 {
351 Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
352 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
353 {
354 ServerCcb = Ccb;
355 break;
356 }
357 CurrentEntry = CurrentEntry->Flink;
358 }
359
360 /*
361 * No one is listening to me?! I'm so lonely... :(
362 */
363
364 if (ServerCcb == NULL)
365 {
366 /* Not found, bail out with error for FILE_OPEN requests. */
367 DPRINT("No listening server CCB found!\n");
368 if (ClientCcb->Data)
369 {
370 ExFreePool(ClientCcb->Data);
371 }
372
373 ExFreePool(ClientCcb);
374 KeUnlockMutex(&Fcb->CcbListLock);
375 Irp->IoStatus.Status = STATUS_OBJECT_PATH_NOT_FOUND;
376 IoCompleteRequest(Irp, IO_NO_INCREMENT);
377 return STATUS_OBJECT_PATH_NOT_FOUND;
378 }
379 }
380 else
381 {
382 /* Signal the server thread and remove it from the waiter list */
383 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
384 NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
385 }
386 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
387 }
388 else if (IsListEmpty(&Fcb->ServerCcbListHead))
389 {
390 DPRINT("No server fcb found!\n");
391
392 if (ClientCcb->Data)
393 {
394 ExFreePool(ClientCcb->Data);
395 }
396
397 ExFreePool(ClientCcb);
398
399 KeUnlockMutex(&Fcb->CcbListLock);
400 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
401 IoCompleteRequest(Irp, IO_NO_INCREMENT);
402 return STATUS_UNSUCCESSFUL;
403 }
404 #endif
405
406 /*
407 * Step 4. Add the client CCB to a list and connect it if possible.
408 */
409
410 /* Add the client CCB to the pipe CCB list. */
411 InsertTailList(&Fcb->ClientCcbListHead, &ClientCcb->CcbListEntry);
412
413 /* Connect to listening server side */
414 if (ServerCcb)
415 {
416 ClientCcb->OtherSide = ServerCcb;
417 ServerCcb->OtherSide = ClientCcb;
418 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
419 ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
420 KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
421 }
422
423 KeUnlockMutex(&Fcb->CcbListLock);
424
425 FileObject->FsContext = Fcb;
426 FileObject->FsContext2 = ClientCcb;
427 FileObject->Flags |= FO_NAMED_PIPE;
428
429 Irp->IoStatus.Status = STATUS_SUCCESS;
430 IoCompleteRequest(Irp, IO_NO_INCREMENT);
431
432 DPRINT("Success!\n");
433
434 return STATUS_SUCCESS;
435 }
436
437
438 NTSTATUS NTAPI
439 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
440 PIRP Irp)
441 {
442 PEXTENDED_IO_STACK_LOCATION IoStack;
443 PFILE_OBJECT FileObject;
444 PNPFS_VCB Vcb;
445 PNPFS_FCB Fcb;
446 PNPFS_CCB Ccb;
447 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
448 BOOLEAN NewPipe = FALSE;
449
450 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
451
452 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
453 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
454 FileObject = IoStack->FileObject;
455 DPRINT("FileObject %p\n", FileObject);
456 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
457
458 Buffer = IoStack->Parameters.CreatePipe.Parameters;
459
460 Irp->IoStatus.Information = 0;
461
462 if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
463 (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
464 {
465 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
466 IoCompleteRequest(Irp, IO_NO_INCREMENT);
467 return STATUS_INVALID_PARAMETER;
468 }
469
470 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
471 if (Ccb == NULL)
472 {
473 Irp->IoStatus.Status = STATUS_NO_MEMORY;
474 IoCompleteRequest(Irp, IO_NO_INCREMENT);
475 return STATUS_NO_MEMORY;
476 }
477
478 Ccb->Type = CCB_PIPE;
479 Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
480 KeLockMutex(&Vcb->PipeListLock);
481
482 /*
483 * First search for existing Pipe with the same name.
484 */
485 Fcb = NpfsFindPipe(Vcb,
486 &FileObject->FileName);
487 if (Fcb != NULL)
488 {
489 /*
490 * Found Pipe with the same name. Check if we are
491 * allowed to use it.
492 */
493 KeUnlockMutex(&Vcb->PipeListLock);
494
495 if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
496 {
497 DPRINT("Out of instances.\n");
498 ExFreePool(Ccb);
499 Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
500 IoCompleteRequest(Irp, IO_NO_INCREMENT);
501 return STATUS_INSTANCE_NOT_AVAILABLE;
502 }
503
504 if (Fcb->MaximumInstances != Buffer->MaximumInstances ||
505 Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart ||
506 Fcb->PipeType != Buffer->NamedPipeType)
507 {
508 DPRINT("Asked for invalid pipe mode.\n");
509 ExFreePool(Ccb);
510 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
511 IoCompleteRequest(Irp, IO_NO_INCREMENT);
512 return STATUS_ACCESS_DENIED;
513 }
514 }
515 else
516 {
517 NewPipe = TRUE;
518 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
519 if (Fcb == NULL)
520 {
521 KeUnlockMutex(&Vcb->PipeListLock);
522 ExFreePool(Ccb);
523 Irp->IoStatus.Status = STATUS_NO_MEMORY;
524 Irp->IoStatus.Information = 0;
525 IoCompleteRequest(Irp, IO_NO_INCREMENT);
526 return STATUS_NO_MEMORY;
527 }
528
529 Fcb->Type = FCB_PIPE;
530 Fcb->Vcb = Vcb;
531 Fcb->PipeName.Length = FileObject->FileName.Length;
532 Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
533 Fcb->PipeName.Buffer = ExAllocatePool(NonPagedPool, Fcb->PipeName.MaximumLength);
534 if (Fcb->PipeName.Buffer == NULL)
535 {
536 KeUnlockMutex(&Vcb->PipeListLock);
537 ExFreePool(Fcb);
538 ExFreePool(Ccb);
539 Irp->IoStatus.Status = STATUS_NO_MEMORY;
540 Irp->IoStatus.Information = 0;
541 IoCompleteRequest(Irp, IO_NO_INCREMENT);
542 return STATUS_NO_MEMORY;
543 }
544
545 RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName);
546
547 InitializeListHead(&Fcb->ServerCcbListHead);
548 InitializeListHead(&Fcb->ClientCcbListHead);
549 InitializeListHead(&Fcb->WaiterListHead);
550 KeInitializeMutex(&Fcb->CcbListLock, 0);
551
552 Fcb->PipeType = Buffer->NamedPipeType;
553 Fcb->ServerReadMode = Buffer->ReadMode;
554 /* MSDN documentation reads that clients always start off in byte mode */
555 Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE;
556
557 Fcb->CompletionMode = Buffer->CompletionMode;
558 switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
559 {
560 case FILE_SHARE_READ:
561 Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND;
562 break;
563 case FILE_SHARE_WRITE:
564 Fcb->PipeConfiguration = FILE_PIPE_INBOUND;
565 break;
566 case FILE_SHARE_READ|FILE_SHARE_WRITE:
567 Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
568 break;
569 }
570 Fcb->MaximumInstances = Buffer->MaximumInstances;
571 Fcb->CurrentInstances = 0;
572 Fcb->TimeOut = Buffer->DefaultTimeout;
573 if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
574 Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
575 {
576 if (Buffer->InboundQuota == 0)
577 {
578 Fcb->InboundQuota = Vcb->DefaultQuota;
579 }
580 else
581 {
582 Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
583 if (Fcb->InboundQuota < Vcb->MinQuota)
584 {
585 Fcb->InboundQuota = Vcb->MinQuota;
586 }
587 else if (Fcb->InboundQuota > Vcb->MaxQuota)
588 {
589 Fcb->InboundQuota = Vcb->MaxQuota;
590 }
591 }
592 }
593 else
594 {
595 Fcb->InboundQuota = 0;
596 }
597
598 if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
599 {
600 if (Buffer->OutboundQuota == 0)
601 {
602 Fcb->OutboundQuota = Vcb->DefaultQuota;
603 }
604 else
605 {
606 Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
607 if (Fcb->OutboundQuota < Vcb->MinQuota)
608 {
609 Fcb->OutboundQuota = Vcb->MinQuota;
610 }
611 else if (Fcb->OutboundQuota > Vcb->MaxQuota)
612 {
613 Fcb->OutboundQuota = Vcb->MaxQuota;
614 }
615 }
616 }
617 else
618 {
619 Fcb->OutboundQuota = 0;
620 }
621
622 InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry);
623 KeUnlockMutex(&Vcb->PipeListLock);
624 }
625
626 if (Fcb->InboundQuota)
627 {
628 Ccb->Data = ExAllocatePool(PagedPool, Fcb->InboundQuota);
629 if (Ccb->Data == NULL)
630 {
631 ExFreePool(Ccb);
632
633 if (NewPipe)
634 {
635 KeLockMutex(&Vcb->PipeListLock);
636 RemoveEntryList(&Fcb->PipeListEntry);
637 KeUnlockMutex(&Vcb->PipeListLock);
638 RtlFreeUnicodeString(&Fcb->PipeName);
639 ExFreePool(Fcb);
640 }
641
642 Irp->IoStatus.Status = STATUS_NO_MEMORY;
643 IoCompleteRequest(Irp, IO_NO_INCREMENT);
644 return STATUS_NO_MEMORY;
645 }
646 }
647 else
648 {
649 Ccb->Data = NULL;
650 }
651
652 Ccb->ReadPtr = Ccb->Data;
653 Ccb->WritePtr = Ccb->Data;
654 Ccb->ReadDataAvailable = 0;
655 Ccb->WriteQuotaAvailable = Fcb->InboundQuota;
656 Ccb->MaxDataLength = Fcb->InboundQuota;
657 InitializeListHead(&Ccb->ReadRequestListHead);
658 ExInitializeFastMutex(&Ccb->DataListLock);
659
660 Fcb->CurrentInstances++;
661
662 Ccb->Fcb = Fcb;
663 Ccb->PipeEnd = FILE_PIPE_SERVER_END;
664 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
665 Ccb->OtherSide = NULL;
666
667 DPRINT("CCB: %p\n", Ccb);
668
669 KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE);
670 KeInitializeEvent(&Ccb->ReadEvent, NotificationEvent, FALSE);
671 KeInitializeEvent(&Ccb->WriteEvent, NotificationEvent, FALSE);
672
673 KeLockMutex(&Fcb->CcbListLock);
674 InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry);
675 KeUnlockMutex(&Fcb->CcbListLock);
676
677 FileObject->FsContext = Fcb;
678 FileObject->FsContext2 = Ccb;
679 FileObject->Flags |= FO_NAMED_PIPE;
680
681 Irp->IoStatus.Status = STATUS_SUCCESS;
682 IoCompleteRequest(Irp, IO_NO_INCREMENT);
683
684 DPRINT("Success!\n");
685
686 return STATUS_SUCCESS;
687 }
688
689
690 NTSTATUS NTAPI
691 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
692 PIRP Irp)
693 {
694 PNPFS_VCB Vcb;
695 PIO_STACK_LOCATION IoStack;
696 PFILE_OBJECT FileObject;
697 PNPFS_CCB Ccb, OtherSide;
698 PNPFS_FCB Fcb;
699 BOOLEAN Server;
700
701 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
702
703 IoStack = IoGetCurrentIrpStackLocation(Irp);
704 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
705 FileObject = IoStack->FileObject;
706 Ccb = FileObject->FsContext2;
707
708 if (Ccb == NULL)
709 {
710 DPRINT("Success!\n");
711 Irp->IoStatus.Status = STATUS_SUCCESS;
712 Irp->IoStatus.Information = 0;
713 IoCompleteRequest(Irp, IO_NO_INCREMENT);
714 return STATUS_SUCCESS;
715 }
716
717 if (Ccb->Type == CCB_DEVICE)
718 {
719 DPRINT("Cleanup the file system!\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 if (Ccb->Type == CCB_DIRECTORY)
727 {
728 DPRINT("Cleanup the root directory!\n");
729 Irp->IoStatus.Status = STATUS_SUCCESS;
730 Irp->IoStatus.Information = 0;
731 IoCompleteRequest(Irp, IO_NO_INCREMENT);
732 return STATUS_SUCCESS;
733 }
734
735 DPRINT("CCB %p\n", Ccb);
736 Fcb = Ccb->Fcb;
737
738 DPRINT("Cleaning pipe %wZ\n", &Fcb->PipeName);
739
740 KeLockMutex(&Fcb->CcbListLock);
741
742 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
743
744 if (Server)
745 {
746 /* FIXME: Clean up existing connections here ?? */
747 DPRINT("Server\n");
748 }
749 else
750 {
751 DPRINT("Client\n");
752 }
753 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
754 {
755 OtherSide = Ccb->OtherSide;
756 /* Lock the server first */
757 if (Server)
758 {
759 ExAcquireFastMutex(&Ccb->DataListLock);
760 ExAcquireFastMutex(&OtherSide->DataListLock);
761 }
762 else
763 {
764 ExAcquireFastMutex(&OtherSide->DataListLock);
765 ExAcquireFastMutex(&Ccb->DataListLock);
766 }
767 OtherSide->OtherSide = NULL;
768 /*
769 * Signaling the write event. If is possible that an other
770 * thread waits for an empty buffer.
771 */
772 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
773 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
774 if (Server)
775 {
776 ExReleaseFastMutex(&OtherSide->DataListLock);
777 ExReleaseFastMutex(&Ccb->DataListLock);
778 }
779 else
780 {
781 ExReleaseFastMutex(&Ccb->DataListLock);
782 ExReleaseFastMutex(&OtherSide->DataListLock);
783 }
784 }
785 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
786 {
787 PLIST_ENTRY Entry;
788 PNPFS_WAITER_ENTRY WaitEntry = NULL;
789 BOOLEAN Complete = FALSE;
790 KIRQL oldIrql;
791 PIRP tmpIrp;
792
793 Entry = Ccb->Fcb->WaiterListHead.Flink;
794 while (Entry != &Ccb->Fcb->WaiterListHead)
795 {
796 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
797 if (WaitEntry->Ccb == Ccb)
798 {
799 RemoveEntryList(Entry);
800 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
801 IoAcquireCancelSpinLock(&oldIrql);
802 if (!tmpIrp->Cancel)
803 {
804 (void)IoSetCancelRoutine(tmpIrp, NULL);
805 Complete = TRUE;
806 }
807 IoReleaseCancelSpinLock(oldIrql);
808 if (Complete)
809 {
810 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
811 tmpIrp->IoStatus.Information = 0;
812 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
813 }
814 break;
815 }
816 Entry = Entry->Flink;
817 }
818
819 }
820 Ccb->PipeState = FILE_PIPE_CLOSING_STATE;
821
822 KeUnlockMutex(&Fcb->CcbListLock);
823
824 ExAcquireFastMutex(&Ccb->DataListLock);
825 if (Ccb->Data)
826 {
827 ExFreePool(Ccb->Data);
828 Ccb->Data = NULL;
829 Ccb->ReadPtr = NULL;
830 Ccb->WritePtr = NULL;
831 }
832 ExReleaseFastMutex(&Ccb->DataListLock);
833
834 Irp->IoStatus.Status = STATUS_SUCCESS;
835 Irp->IoStatus.Information = 0;
836 IoCompleteRequest(Irp, IO_NO_INCREMENT);
837
838 DPRINT("Success!\n");
839
840 return STATUS_SUCCESS;
841 }
842
843 NTSTATUS NTAPI
844 NpfsClose(PDEVICE_OBJECT DeviceObject,
845 PIRP Irp)
846 {
847 PIO_STACK_LOCATION IoStack;
848 PFILE_OBJECT FileObject;
849 PNPFS_VCB Vcb;
850 PNPFS_FCB Fcb;
851 PNPFS_CCB Ccb;
852 BOOLEAN Server;
853
854 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
855
856 IoStack = IoGetCurrentIrpStackLocation(Irp);
857 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
858 FileObject = IoStack->FileObject;
859 Ccb = FileObject->FsContext2;
860
861 if (Ccb == NULL)
862 {
863 DPRINT("Success!\n");
864 Irp->IoStatus.Status = STATUS_SUCCESS;
865 Irp->IoStatus.Information = 0;
866 IoCompleteRequest(Irp, IO_NO_INCREMENT);
867 return STATUS_SUCCESS;
868 }
869
870 if (Ccb->Type == CCB_DEVICE)
871 {
872 DPRINT("Closing the file system!\n");
873
874 ExFreePool(Ccb);
875 FileObject->FsContext = NULL;
876 FileObject->FsContext2 = NULL;
877
878 Irp->IoStatus.Status = STATUS_SUCCESS;
879 Irp->IoStatus.Information = 0;
880 IoCompleteRequest(Irp, IO_NO_INCREMENT);
881 return STATUS_SUCCESS;
882 }
883
884 if (Ccb->Type == CCB_DIRECTORY)
885 {
886 DPRINT("Closing the root directory!\n");
887
888 if (Ccb->u.Directory.SearchPattern.Buffer != NULL)
889 ExFreePool(Ccb->u.Directory.SearchPattern.Buffer);
890
891 ExFreePool(Ccb);
892 FileObject->FsContext = NULL;
893 FileObject->FsContext2 = NULL;
894
895 Irp->IoStatus.Status = STATUS_SUCCESS;
896 Irp->IoStatus.Information = 0;
897 IoCompleteRequest(Irp, IO_NO_INCREMENT);
898 return STATUS_SUCCESS;
899 }
900
901 DPRINT("CCB %p\n", Ccb);
902 Fcb = Ccb->Fcb;
903
904 DPRINT("Closing pipe %wZ\n", &Fcb->PipeName);
905
906 KeLockMutex(&Fcb->CcbListLock);
907
908 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
909
910 if (Server)
911 {
912 DPRINT("Server\n");
913 Fcb->CurrentInstances--;
914 }
915 else
916 {
917 DPRINT("Client\n");
918 }
919
920 /* Disconnect the pipes */
921 if (Ccb->OtherSide)
922 {
923 Ccb->OtherSide->OtherSide = NULL;
924 Ccb->OtherSide = NULL;
925 }
926
927 ASSERT(Ccb->PipeState == FILE_PIPE_CLOSING_STATE);
928
929 FileObject->FsContext2 = NULL;
930
931 RemoveEntryList(&Ccb->CcbListEntry);
932
933 ExFreePool(Ccb);
934
935 KeUnlockMutex(&Fcb->CcbListLock);
936
937 if (IsListEmpty(&Fcb->ServerCcbListHead) &&
938 IsListEmpty(&Fcb->ClientCcbListHead))
939 {
940 KeLockMutex(&Vcb->PipeListLock);
941 RemoveEntryList(&Fcb->PipeListEntry);
942 KeUnlockMutex(&Vcb->PipeListLock);
943 RtlFreeUnicodeString(&Fcb->PipeName);
944 ExFreePool(Fcb);
945 FileObject->FsContext = NULL;
946 }
947
948 Irp->IoStatus.Status = STATUS_SUCCESS;
949 Irp->IoStatus.Information = 0;
950 IoCompleteRequest(Irp, IO_NO_INCREMENT);
951
952 DPRINT("Success!\n");
953
954 return STATUS_SUCCESS;
955 }
956
957 /* EOF */