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