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