[CLT2012]
[reactos.git] / 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 if (IoSetCancelRoutine(Irp, NULL) != NULL)
137 {
138 IoReleaseCancelSpinLock(oldIrql);
139 return Waiter->Ccb;
140 }
141 }
142 IoReleaseCancelSpinLock(oldIrql);
143 }
144
145 CurrentEntry = CurrentEntry->Flink;
146 }
147
148 return NULL;
149 }
150
151
152 static VOID
153 NpfsSignalAndRemoveListeningServerInstance(PNPFS_FCB Fcb,
154 PNPFS_CCB Ccb)
155 {
156 PLIST_ENTRY CurrentEntry;
157 PNPFS_WAITER_ENTRY Waiter;
158 PIRP Irp;
159
160 CurrentEntry = Fcb->WaiterListHead.Flink;
161 while (CurrentEntry != &Fcb->WaiterListHead)
162 {
163 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
164 if (Waiter->Ccb == Ccb)
165 {
166 DPRINT("Server found! CCB %p\n", Waiter->Ccb);
167
168 RemoveEntryList(&Waiter->Entry);
169 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
170 Irp->IoStatus.Status = STATUS_SUCCESS;
171 Irp->IoStatus.Information = 0;
172 IoCompleteRequest(Irp, IO_NO_INCREMENT);
173 break;
174 }
175 CurrentEntry = CurrentEntry->Flink;
176 }
177 }
178
179
180 static VOID
181 NpfsOpenFileSystem(PNPFS_FCB Fcb,
182 PFILE_OBJECT FileObject,
183 PIO_STATUS_BLOCK IoStatus)
184 {
185 PNPFS_CCB Ccb;
186
187 DPRINT("NpfsOpenFileSystem()\n");
188
189 Ccb = NpfsAllocateCcb(CCB_DEVICE, Fcb);
190 if (Ccb == NULL)
191 {
192 IoStatus->Status = STATUS_NO_MEMORY;
193 return;
194 }
195
196 Ccb->FileObject = FileObject;
197
198 FileObject->FsContext = Fcb;
199 FileObject->FsContext2 = Ccb;
200
201 IoStatus->Information = FILE_OPENED;
202 IoStatus->Status = STATUS_SUCCESS;
203
204 return;
205 }
206
207
208 static VOID
209 NpfsOpenRootDirectory(PNPFS_FCB Fcb,
210 PFILE_OBJECT FileObject,
211 PIO_STATUS_BLOCK IoStatus)
212 {
213 PNPFS_CCB Ccb;
214
215 DPRINT("NpfsOpenRootDirectory()\n");
216
217 Ccb = NpfsAllocateCcb(CCB_DIRECTORY, Fcb);
218 if (Ccb == NULL)
219 {
220 IoStatus->Status = STATUS_NO_MEMORY;
221 return;
222 }
223
224 Ccb->FileObject = FileObject;
225
226 FileObject->FsContext = Fcb;
227 FileObject->FsContext2 = Ccb;
228
229 IoStatus->Information = FILE_OPENED;
230 IoStatus->Status = STATUS_SUCCESS;
231
232 return;
233 }
234
235
236 NTSTATUS NTAPI
237 NpfsCreate(PDEVICE_OBJECT DeviceObject,
238 PIRP Irp)
239 {
240 PEXTENDED_IO_STACK_LOCATION IoStack;
241 PUNICODE_STRING FileName;
242 PFILE_OBJECT FileObject;
243 PFILE_OBJECT RelatedFileObject;
244 PNPFS_FCB Fcb;
245 PNPFS_CCB ClientCcb;
246 PNPFS_CCB ServerCcb = NULL;
247 PNPFS_VCB Vcb;
248 ACCESS_MASK DesiredAccess;
249 NTSTATUS Status;
250 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
251 BOOLEAN SpecialAccess;
252 #endif
253
254 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
255
256 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
257 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
258 FileObject = IoStack->FileObject;
259 RelatedFileObject = FileObject->RelatedFileObject;
260 FileName = &FileObject->FileName;
261 DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
262
263 DPRINT("FileObject %p\n", FileObject);
264 DPRINT("FileName %wZ\n", &FileObject->FileName);
265
266 Irp->IoStatus.Information = 0;
267
268 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
269 SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES);
270 if (SpecialAccess)
271 {
272 DPRINT("NpfsCreate() open client end for special use!\n");
273 }
274 #endif
275
276 DPRINT("FileName->Length: %hu RelatedFileObject: %p\n", FileName->Length, RelatedFileObject);
277
278 /* Open the file system */
279 if (FileName->Length == 0 &&
280 (RelatedFileObject == NULL || ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DEVICE))
281 {
282 DPRINT("Open the file system\n");
283
284 NpfsOpenFileSystem(Vcb->DeviceFcb,
285 FileObject,
286 &Irp->IoStatus);
287
288 Status = Irp->IoStatus.Status;
289 IoCompleteRequest(Irp, IO_NO_INCREMENT);
290 return Status;
291 }
292
293 /* Open the root directory */
294 if ((FileName->Length == 2 && FileName->Buffer[0] == L'\\' && RelatedFileObject == NULL) ||
295 (FileName->Length == 0 && ((PNPFS_CCB)RelatedFileObject->FsContext2)->Type == CCB_DIRECTORY))
296 {
297 DPRINT("Open the root directory\n");
298
299 NpfsOpenRootDirectory(Vcb->RootFcb,
300 FileObject,
301 &Irp->IoStatus);
302
303 Status = Irp->IoStatus.Status;
304 IoCompleteRequest(Irp, IO_NO_INCREMENT);
305 return Status;
306 }
307
308
309 /*
310 * Step 1. Find the pipe we're trying to open.
311 */
312 KeLockMutex(&Vcb->PipeListLock);
313 Fcb = NpfsFindPipe(Vcb, &FileObject->FileName);
314 if (Fcb == NULL)
315 {
316 /* Not found, bail out with error. */
317 DPRINT("No pipe found!\n");
318 KeUnlockMutex(&Vcb->PipeListLock);
319 Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
320 IoCompleteRequest(Irp, IO_NO_INCREMENT);
321 return STATUS_OBJECT_NAME_NOT_FOUND;
322 }
323
324 KeUnlockMutex(&Vcb->PipeListLock);
325
326 /*
327 * Acquire the lock for CCB lists. From now on no modifications to the
328 * CCB lists are allowed, because it can cause various misconsistencies.
329 */
330 KeLockMutex(&Fcb->CcbListLock);
331
332 /*
333 * Step 2. Create the client CCB.
334 */
335 ClientCcb = NpfsAllocateCcb(CCB_PIPE, Fcb);
336 if (ClientCcb == NULL)
337 {
338 DPRINT("No memory!\n");
339 KeUnlockMutex(&Fcb->CcbListLock);
340 Irp->IoStatus.Status = STATUS_NO_MEMORY;
341 IoCompleteRequest(Irp, IO_NO_INCREMENT);
342 return STATUS_NO_MEMORY;
343 }
344
345 ClientCcb->FileObject = FileObject;
346 ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
347 ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END;
348 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
349 ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
350 #else
351 ClientCcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
352 #endif
353 InitializeListHead(&ClientCcb->ReadRequestListHead);
354
355 DPRINT("CCB: %p\n", ClientCcb);
356
357 /* Initialize data list. */
358 if (Fcb->OutboundQuota)
359 {
360 ClientCcb->Data = ExAllocatePoolWithTag(PagedPool,
361 Fcb->OutboundQuota,
362 TAG_NPFS_CCB_DATA);
363 if (ClientCcb->Data == NULL)
364 {
365 DPRINT("No memory!\n");
366 NpfsDereferenceCcb(ClientCcb);
367 KeUnlockMutex(&Fcb->CcbListLock);
368 Irp->IoStatus.Status = STATUS_NO_MEMORY;
369 IoCompleteRequest(Irp, IO_NO_INCREMENT);
370 return STATUS_NO_MEMORY;
371 }
372 }
373 else
374 {
375 ClientCcb->Data = NULL;
376 }
377
378 ClientCcb->ReadPtr = ClientCcb->Data;
379 ClientCcb->WritePtr = ClientCcb->Data;
380 ClientCcb->ReadDataAvailable = 0;
381 ClientCcb->WriteQuotaAvailable = Fcb->OutboundQuota;
382 ClientCcb->MaxDataLength = Fcb->OutboundQuota;
383 ExInitializeFastMutex(&ClientCcb->DataListLock);
384 KeInitializeEvent(&ClientCcb->ConnectEvent, SynchronizationEvent, FALSE);
385 KeInitializeEvent(&ClientCcb->ReadEvent, NotificationEvent, FALSE);
386 KeInitializeEvent(&ClientCcb->WriteEvent, NotificationEvent, FALSE);
387
388
389 /*
390 * Step 3. Search for listening server CCB.
391 */
392 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
393 if (!SpecialAccess)
394 {
395 #endif
396 /*
397 * WARNING: Point of no return! Once we get the server CCB it's
398 * possible that we completed a wait request and so we have to
399 * complete even this request.
400 */
401
402 ServerCcb = NpfsFindListeningServerInstance(Fcb);
403 if (ServerCcb == NULL)
404 {
405 PLIST_ENTRY CurrentEntry;
406 PNPFS_CCB Ccb;
407
408 /*
409 * If no waiting server CCB was found then try to pick
410 * one of the listing server CCB on the pipe.
411 */
412
413 CurrentEntry = Fcb->ServerCcbListHead.Flink;
414 while (CurrentEntry != &Fcb->ServerCcbListHead)
415 {
416 Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
417 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
418 {
419 ServerCcb = Ccb;
420 break;
421 }
422 CurrentEntry = CurrentEntry->Flink;
423 }
424
425 /*
426 * No one is listening to me?! I'm so lonely... :(
427 */
428
429 if (ServerCcb == NULL)
430 {
431 /* Not found, bail out with error for FILE_OPEN requests. */
432 DPRINT("No listening server CCB found!\n");
433 if (ClientCcb->Data)
434 {
435 ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA);
436 }
437
438 NpfsDereferenceCcb(ClientCcb);
439 KeUnlockMutex(&Fcb->CcbListLock);
440 Irp->IoStatus.Status = STATUS_OBJECT_PATH_NOT_FOUND;
441 IoCompleteRequest(Irp, IO_NO_INCREMENT);
442 return STATUS_OBJECT_PATH_NOT_FOUND;
443 }
444 }
445 else
446 {
447 /* Signal the server thread and remove it from the waiter list */
448 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
449 NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
450 }
451 #ifndef USING_PROPER_NPFS_WAIT_SEMANTICS
452 }
453 else if (IsListEmpty(&Fcb->ServerCcbListHead))
454 {
455 DPRINT("No server fcb found!\n");
456
457 if (ClientCcb->Data)
458 {
459 ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA);
460 }
461
462 NpfsDereferenceCcb(ClientCcb);
463
464 KeUnlockMutex(&Fcb->CcbListLock);
465 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
466 IoCompleteRequest(Irp, IO_NO_INCREMENT);
467 return STATUS_UNSUCCESSFUL;
468 }
469 #endif
470
471 /*
472 * Step 4. Add the client CCB to a list and connect it if possible.
473 */
474
475 /* Add the client CCB to the pipe CCB list. */
476 InsertTailList(&Fcb->ClientCcbListHead, &ClientCcb->CcbListEntry);
477
478 /* Connect to listening server side */
479 if (ServerCcb)
480 {
481 NpfsCcbSetOtherSide(ClientCcb, ServerCcb);
482 NpfsCcbSetOtherSide(ServerCcb, ClientCcb);
483 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
484 ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
485 KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
486 }
487
488 KeUnlockMutex(&Fcb->CcbListLock);
489
490 FileObject->FsContext = Fcb;
491 FileObject->FsContext2 = ClientCcb;
492 FileObject->Flags |= FO_NAMED_PIPE;
493
494 Irp->IoStatus.Status = STATUS_SUCCESS;
495 IoCompleteRequest(Irp, IO_NO_INCREMENT);
496
497 DPRINT("Success!\n");
498
499 return STATUS_SUCCESS;
500 }
501
502
503 NTSTATUS NTAPI
504 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
505 PIRP Irp)
506 {
507 PEXTENDED_IO_STACK_LOCATION IoStack;
508 PFILE_OBJECT FileObject;
509 PNPFS_VCB Vcb;
510 PNPFS_FCB Fcb;
511 PNPFS_CCB Ccb;
512 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
513 BOOLEAN NewPipe = FALSE;
514
515 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
516
517 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
518 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
519 FileObject = IoStack->FileObject;
520 DPRINT("FileObject %p\n", FileObject);
521 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
522
523 Buffer = IoStack->Parameters.CreatePipe.Parameters;
524
525 Irp->IoStatus.Information = 0;
526
527 if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
528 (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
529 {
530 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
531 IoCompleteRequest(Irp, IO_NO_INCREMENT);
532 return STATUS_INVALID_PARAMETER;
533 }
534
535 KeLockMutex(&Vcb->PipeListLock);
536
537 /*
538 * First search for existing Pipe with the same name.
539 */
540 Fcb = NpfsFindPipe(Vcb, &FileObject->FileName);
541 if (Fcb != NULL)
542 {
543 /*
544 * Found Pipe with the same name. Check if we are
545 * allowed to use it.
546 */
547 KeUnlockMutex(&Vcb->PipeListLock);
548
549 if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
550 {
551 DPRINT("Out of instances.\n");
552 Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
553 IoCompleteRequest(Irp, IO_NO_INCREMENT);
554 return STATUS_INSTANCE_NOT_AVAILABLE;
555 }
556
557 if (Fcb->MaximumInstances != Buffer->MaximumInstances ||
558 Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart ||
559 Fcb->PipeType != Buffer->NamedPipeType)
560 {
561 DPRINT("Asked for invalid pipe mode.\n");
562 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
563 IoCompleteRequest(Irp, IO_NO_INCREMENT);
564 return STATUS_ACCESS_DENIED;
565 }
566 }
567 else
568 {
569 NewPipe = TRUE;
570 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPFS_FCB), TAG_NPFS_FCB);
571 if (Fcb == NULL)
572 {
573 KeUnlockMutex(&Vcb->PipeListLock);
574 Irp->IoStatus.Status = STATUS_NO_MEMORY;
575 Irp->IoStatus.Information = 0;
576 IoCompleteRequest(Irp, IO_NO_INCREMENT);
577 return STATUS_NO_MEMORY;
578 }
579
580 Fcb->Type = FCB_PIPE;
581 Fcb->Vcb = Vcb;
582 Fcb->PipeName.Length = FileObject->FileName.Length;
583 Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
584 Fcb->PipeName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
585 Fcb->PipeName.MaximumLength,
586 TAG_NPFS_NAMEBLOCK);
587 if (Fcb->PipeName.Buffer == NULL)
588 {
589 KeUnlockMutex(&Vcb->PipeListLock);
590 ExFreePoolWithTag(Fcb, TAG_NPFS_FCB);
591 Irp->IoStatus.Status = STATUS_NO_MEMORY;
592 Irp->IoStatus.Information = 0;
593 IoCompleteRequest(Irp, IO_NO_INCREMENT);
594 return STATUS_NO_MEMORY;
595 }
596
597 RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName);
598
599 InitializeListHead(&Fcb->ServerCcbListHead);
600 InitializeListHead(&Fcb->ClientCcbListHead);
601 InitializeListHead(&Fcb->WaiterListHead);
602 KeInitializeMutex(&Fcb->CcbListLock, 0);
603
604 Fcb->PipeType = Buffer->NamedPipeType;
605 Fcb->ServerReadMode = Buffer->ReadMode;
606 /* MSDN documentation reads that clients always start off in byte mode */
607 Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE;
608
609 Fcb->CompletionMode = Buffer->CompletionMode;
610 switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
611 {
612 case FILE_SHARE_READ:
613 Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND;
614 break;
615 case FILE_SHARE_WRITE:
616 Fcb->PipeConfiguration = FILE_PIPE_INBOUND;
617 break;
618 case FILE_SHARE_READ|FILE_SHARE_WRITE:
619 Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
620 break;
621 }
622 Fcb->MaximumInstances = Buffer->MaximumInstances;
623 Fcb->CurrentInstances = 0;
624 Fcb->TimeOut = Buffer->DefaultTimeout;
625 if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
626 Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
627 {
628 if (Buffer->InboundQuota == 0)
629 {
630 Fcb->InboundQuota = Vcb->DefaultQuota;
631 }
632 else
633 {
634 Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
635 if (Fcb->InboundQuota < Vcb->MinQuota)
636 {
637 Fcb->InboundQuota = Vcb->MinQuota;
638 }
639 else if (Fcb->InboundQuota > Vcb->MaxQuota)
640 {
641 Fcb->InboundQuota = Vcb->MaxQuota;
642 }
643 }
644 }
645 else
646 {
647 Fcb->InboundQuota = 0;
648 }
649
650 if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
651 {
652 if (Buffer->OutboundQuota == 0)
653 {
654 Fcb->OutboundQuota = Vcb->DefaultQuota;
655 }
656 else
657 {
658 Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
659 if (Fcb->OutboundQuota < Vcb->MinQuota)
660 {
661 Fcb->OutboundQuota = Vcb->MinQuota;
662 }
663 else if (Fcb->OutboundQuota > Vcb->MaxQuota)
664 {
665 Fcb->OutboundQuota = Vcb->MaxQuota;
666 }
667 }
668 }
669 else
670 {
671 Fcb->OutboundQuota = 0;
672 }
673
674 InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry);
675 KeUnlockMutex(&Vcb->PipeListLock);
676 }
677
678 Ccb = NpfsAllocateCcb(CCB_PIPE, Fcb);
679 if (Ccb == NULL)
680 {
681 if (NewPipe)
682 {
683 NpfsDeleteFcb(Fcb);
684 }
685
686 Irp->IoStatus.Status = STATUS_NO_MEMORY;
687 IoCompleteRequest(Irp, IO_NO_INCREMENT);
688 return STATUS_NO_MEMORY;
689 }
690
691 Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
692
693 if (Fcb->InboundQuota)
694 {
695 Ccb->Data = ExAllocatePoolWithTag(PagedPool,
696 Fcb->InboundQuota,
697 TAG_NPFS_CCB_DATA);
698 if (Ccb->Data == NULL)
699 {
700 NpfsDereferenceCcb(Ccb);
701
702 if (NewPipe)
703 {
704 NpfsDeleteFcb(Fcb);
705 }
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 if (IsListEmpty(&Fcb->ServerCcbListHead) &&
1008 IsListEmpty(&Fcb->ClientCcbListHead))
1009 {
1010 NpfsDeleteFcb(Fcb);
1011 FileObject->FsContext = NULL;
1012 }
1013
1014 Irp->IoStatus.Status = STATUS_SUCCESS;
1015 Irp->IoStatus.Information = 0;
1016 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1017
1018 DPRINT("Success!\n");
1019
1020 return STATUS_SUCCESS;
1021 }
1022
1023 /* EOF */