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