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