[NPFS/KERNEL32]
[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 //#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 ULONG Disposition;
523 ULONG ShareAccess;
524 PNAMED_PIPE_CREATE_PARAMETERS Parameters;
525
526 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
527
528 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
529 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
530 FileObject = IoStack->FileObject;
531 DPRINT("FileObject %p\n", FileObject);
532 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
533
534 Disposition = (IoStack->Parameters.CreatePipe.Options >> 24) & 0xFF;
535 ShareAccess = IoStack->Parameters.CreatePipe.ShareAccess;
536 Parameters = IoStack->Parameters.CreatePipe.Parameters;
537
538 Irp->IoStatus.Information = 0;
539
540 if ((Disposition == FILE_OVERWRITE) ||
541 (Disposition == FILE_OVERWRITE_IF) ||
542 !(ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
543 (ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
544 {
545 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
546 IoCompleteRequest(Irp, IO_NO_INCREMENT);
547 return STATUS_INVALID_PARAMETER;
548 }
549
550 KeLockMutex(&Vcb->PipeListLock);
551
552 /*
553 * First search for existing Pipe with the same name.
554 */
555 Fcb = NpfsFindPipe(Vcb, &FileObject->FileName);
556 if (Fcb != NULL)
557 {
558 /*
559 * Found Pipe with the same name. Check if we are
560 * allowed to use it.
561 */
562 KeUnlockMutex(&Vcb->PipeListLock);
563
564 if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
565 {
566 DPRINT("Out of instances.\n");
567 NpfsDereferenceFcb(Fcb);
568 Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
569 IoCompleteRequest(Irp, IO_NO_INCREMENT);
570 return STATUS_INSTANCE_NOT_AVAILABLE;
571 }
572
573 if (Disposition == FILE_CREATE ||
574 Fcb->MaximumInstances != Parameters->MaximumInstances ||
575 Fcb->TimeOut.QuadPart != Parameters->DefaultTimeout.QuadPart ||
576 Fcb->PipeType != Parameters->NamedPipeType)
577 {
578 DPRINT("Asked for invalid pipe mode.\n");
579 NpfsDereferenceFcb(Fcb);
580 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
581 IoCompleteRequest(Irp, IO_NO_INCREMENT);
582 return STATUS_ACCESS_DENIED;
583 }
584 }
585 else
586 {
587 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPFS_FCB), TAG_NPFS_FCB);
588 if (Fcb == NULL)
589 {
590 KeUnlockMutex(&Vcb->PipeListLock);
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 Fcb->Type = FCB_PIPE;
598 Fcb->Vcb = Vcb;
599 Fcb->RefCount = 1;
600 Fcb->PipeName.Length = FileObject->FileName.Length;
601 Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
602 Fcb->PipeName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
603 Fcb->PipeName.MaximumLength,
604 TAG_NPFS_NAMEBLOCK);
605 if (Fcb->PipeName.Buffer == NULL)
606 {
607 KeUnlockMutex(&Vcb->PipeListLock);
608 ExFreePoolWithTag(Fcb, TAG_NPFS_FCB);
609 Irp->IoStatus.Status = STATUS_NO_MEMORY;
610 Irp->IoStatus.Information = 0;
611 IoCompleteRequest(Irp, IO_NO_INCREMENT);
612 return STATUS_NO_MEMORY;
613 }
614
615 RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName);
616
617 InitializeListHead(&Fcb->ServerCcbListHead);
618 InitializeListHead(&Fcb->ClientCcbListHead);
619 InitializeListHead(&Fcb->WaiterListHead);
620 KeInitializeMutex(&Fcb->CcbListLock, 0);
621
622 Fcb->PipeType = Parameters->NamedPipeType;
623 Fcb->ServerReadMode = Parameters->ReadMode;
624 /* MSDN documentation reads that clients always start off in byte mode */
625 Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE;
626
627 Fcb->CompletionMode = Parameters->CompletionMode;
628 switch (ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
629 {
630 case FILE_SHARE_READ:
631 Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND;
632 break;
633 case FILE_SHARE_WRITE:
634 Fcb->PipeConfiguration = FILE_PIPE_INBOUND;
635 break;
636 case FILE_SHARE_READ|FILE_SHARE_WRITE:
637 Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
638 break;
639 }
640 Fcb->MaximumInstances = Parameters->MaximumInstances;
641 Fcb->CurrentInstances = 0;
642 Fcb->TimeOut = Parameters->DefaultTimeout;
643 if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
644 Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
645 {
646 if (Parameters->InboundQuota == 0)
647 {
648 Fcb->InboundQuota = Vcb->DefaultQuota;
649 }
650 else
651 {
652 Fcb->InboundQuota = PAGE_ROUND_UP(Parameters->InboundQuota);
653 if (Fcb->InboundQuota < Vcb->MinQuota)
654 {
655 Fcb->InboundQuota = Vcb->MinQuota;
656 }
657 else if (Fcb->InboundQuota > Vcb->MaxQuota)
658 {
659 Fcb->InboundQuota = Vcb->MaxQuota;
660 }
661 }
662 }
663 else
664 {
665 Fcb->InboundQuota = 0;
666 }
667
668 if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
669 {
670 if (Parameters->OutboundQuota == 0)
671 {
672 Fcb->OutboundQuota = Vcb->DefaultQuota;
673 }
674 else
675 {
676 Fcb->OutboundQuota = PAGE_ROUND_UP(Parameters->OutboundQuota);
677 if (Fcb->OutboundQuota < Vcb->MinQuota)
678 {
679 Fcb->OutboundQuota = Vcb->MinQuota;
680 }
681 else if (Fcb->OutboundQuota > Vcb->MaxQuota)
682 {
683 Fcb->OutboundQuota = Vcb->MaxQuota;
684 }
685 }
686 }
687 else
688 {
689 Fcb->OutboundQuota = 0;
690 }
691
692 InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry);
693 KeUnlockMutex(&Vcb->PipeListLock);
694 }
695
696 Ccb = NpfsAllocateCcb(CCB_PIPE, Fcb);
697 if (Ccb == NULL)
698 {
699 NpfsDereferenceFcb(Fcb);
700 Irp->IoStatus.Status = STATUS_NO_MEMORY;
701 IoCompleteRequest(Irp, IO_NO_INCREMENT);
702 return STATUS_NO_MEMORY;
703 }
704
705 Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
706
707 if (Fcb->InboundQuota)
708 {
709 Ccb->Data = ExAllocatePoolWithTag(PagedPool,
710 Fcb->InboundQuota,
711 TAG_NPFS_CCB_DATA);
712 if (Ccb->Data == NULL)
713 {
714 NpfsDereferenceCcb(Ccb);
715 NpfsDereferenceFcb(Fcb);
716
717 Irp->IoStatus.Status = STATUS_NO_MEMORY;
718 IoCompleteRequest(Irp, IO_NO_INCREMENT);
719 return STATUS_NO_MEMORY;
720 }
721 }
722 else
723 {
724 Ccb->Data = NULL;
725 }
726
727 Ccb->ReadPtr = Ccb->Data;
728 Ccb->WritePtr = Ccb->Data;
729 Ccb->ReadDataAvailable = 0;
730 Ccb->WriteQuotaAvailable = Fcb->InboundQuota;
731 Ccb->MaxDataLength = Fcb->InboundQuota;
732 InitializeListHead(&Ccb->ReadRequestListHead);
733 ExInitializeFastMutex(&Ccb->DataListLock);
734
735 Fcb->CurrentInstances++;
736
737 Ccb->Fcb = Fcb;
738 Ccb->FileObject = FileObject;
739 Ccb->PipeEnd = FILE_PIPE_SERVER_END;
740 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
741
742 DPRINT("CCB: %p\n", Ccb);
743
744 KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE);
745 KeInitializeEvent(&Ccb->ReadEvent, NotificationEvent, FALSE);
746 KeInitializeEvent(&Ccb->WriteEvent, NotificationEvent, FALSE);
747
748 KeLockMutex(&Fcb->CcbListLock);
749 InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry);
750 KeUnlockMutex(&Fcb->CcbListLock);
751
752 FileObject->FsContext = Fcb;
753 FileObject->FsContext2 = Ccb;
754 FileObject->Flags |= FO_NAMED_PIPE;
755
756 Irp->IoStatus.Status = STATUS_SUCCESS;
757 IoCompleteRequest(Irp, IO_NO_INCREMENT);
758
759 DPRINT("Success!\n");
760
761 return STATUS_SUCCESS;
762 }
763
764
765 NTSTATUS NTAPI
766 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
767 PIRP Irp)
768 {
769 //PNPFS_VCB Vcb;
770 PIO_STACK_LOCATION IoStack;
771 PFILE_OBJECT FileObject;
772 PNPFS_CCB Ccb, OtherSide;
773 PNPFS_FCB Fcb;
774 BOOLEAN Server;
775
776 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
777
778 IoStack = IoGetCurrentIrpStackLocation(Irp);
779 //Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
780 FileObject = IoStack->FileObject;
781 Ccb = FileObject->FsContext2;
782
783 if (Ccb == NULL)
784 {
785 DPRINT("Success!\n");
786 Irp->IoStatus.Status = STATUS_SUCCESS;
787 Irp->IoStatus.Information = 0;
788 IoCompleteRequest(Irp, IO_NO_INCREMENT);
789 return STATUS_SUCCESS;
790 }
791
792 if (Ccb->Type == CCB_DEVICE)
793 {
794 DPRINT("Cleanup the file system!\n");
795 Irp->IoStatus.Status = STATUS_SUCCESS;
796 Irp->IoStatus.Information = 0;
797 IoCompleteRequest(Irp, IO_NO_INCREMENT);
798 return STATUS_SUCCESS;
799 }
800
801 if (Ccb->Type == CCB_DIRECTORY)
802 {
803 DPRINT("Cleanup the root directory!\n");
804 Irp->IoStatus.Status = STATUS_SUCCESS;
805 Irp->IoStatus.Information = 0;
806 IoCompleteRequest(Irp, IO_NO_INCREMENT);
807 return STATUS_SUCCESS;
808 }
809
810 DPRINT("CCB %p\n", Ccb);
811 Fcb = Ccb->Fcb;
812
813 DPRINT("Cleaning pipe %wZ\n", &Fcb->PipeName);
814
815 KeLockMutex(&Fcb->CcbListLock);
816
817 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
818
819 if (Server)
820 {
821 /* FIXME: Clean up existing connections here ?? */
822 DPRINT("Server\n");
823 }
824 else
825 {
826 DPRINT("Client\n");
827 }
828 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
829 {
830 OtherSide = Ccb->OtherSide;
831 ASSERT(OtherSide->OtherSide == Ccb);
832
833 /* Lock the server first */
834 if (Server)
835 {
836 ExAcquireFastMutex(&Ccb->DataListLock);
837 ExAcquireFastMutex(&OtherSide->DataListLock);
838 }
839 else
840 {
841 ExAcquireFastMutex(&OtherSide->DataListLock);
842 ExAcquireFastMutex(&Ccb->DataListLock);
843 }
844
845 /* Unlink FCBs */
846 NpfsCcbSetOtherSide(OtherSide, NULL);
847 NpfsCcbSetOtherSide(Ccb, NULL);
848
849 /*
850 * Signaling the write event. If is possible that an other
851 * thread waits for an empty buffer.
852 */
853 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
854 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
855 if (Server)
856 {
857 ExReleaseFastMutex(&OtherSide->DataListLock);
858 ExReleaseFastMutex(&Ccb->DataListLock);
859 }
860 else
861 {
862 ExReleaseFastMutex(&Ccb->DataListLock);
863 ExReleaseFastMutex(&OtherSide->DataListLock);
864 }
865 }
866 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
867 {
868 PLIST_ENTRY Entry;
869 PNPFS_WAITER_ENTRY WaitEntry = NULL;
870 BOOLEAN Complete = FALSE;
871 KIRQL oldIrql;
872 PIRP tmpIrp;
873
874 Entry = Ccb->Fcb->WaiterListHead.Flink;
875 while (Entry != &Ccb->Fcb->WaiterListHead)
876 {
877 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
878 if (WaitEntry->Ccb == Ccb)
879 {
880 RemoveEntryList(Entry);
881 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
882 IoAcquireCancelSpinLock(&oldIrql);
883 Complete = (NULL != IoSetCancelRoutine(tmpIrp, NULL));
884 IoReleaseCancelSpinLock(oldIrql);
885 if (Complete)
886 {
887 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
888 tmpIrp->IoStatus.Information = 0;
889 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
890 }
891 break;
892 }
893 Entry = Entry->Flink;
894 }
895
896 }
897 Ccb->PipeState = FILE_PIPE_CLOSING_STATE;
898
899 KeUnlockMutex(&Fcb->CcbListLock);
900
901 ExAcquireFastMutex(&Ccb->DataListLock);
902 if (Ccb->Data)
903 {
904 ExFreePoolWithTag(Ccb->Data, TAG_NPFS_CCB_DATA);
905 Ccb->Data = NULL;
906 Ccb->ReadPtr = NULL;
907 Ccb->WritePtr = NULL;
908 }
909 ExReleaseFastMutex(&Ccb->DataListLock);
910
911 Irp->IoStatus.Status = STATUS_SUCCESS;
912 Irp->IoStatus.Information = 0;
913 IoCompleteRequest(Irp, IO_NO_INCREMENT);
914
915 DPRINT("Success!\n");
916
917 return STATUS_SUCCESS;
918 }
919
920 NTSTATUS NTAPI
921 NpfsClose(PDEVICE_OBJECT DeviceObject,
922 PIRP Irp)
923 {
924 PIO_STACK_LOCATION IoStack;
925 PFILE_OBJECT FileObject;
926 //PNPFS_VCB Vcb;
927 PNPFS_FCB Fcb;
928 PNPFS_CCB Ccb;
929 BOOLEAN Server;
930
931 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
932
933 IoStack = IoGetCurrentIrpStackLocation(Irp);
934 //Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
935 FileObject = IoStack->FileObject;
936 Ccb = FileObject->FsContext2;
937
938 if (Ccb == NULL)
939 {
940 DPRINT("Success!\n");
941 Irp->IoStatus.Status = STATUS_SUCCESS;
942 Irp->IoStatus.Information = 0;
943 IoCompleteRequest(Irp, IO_NO_INCREMENT);
944 return STATUS_SUCCESS;
945 }
946
947 if (Ccb->Type == CCB_DEVICE)
948 {
949 DPRINT("Closing the file system!\n");
950
951 NpfsDereferenceCcb(Ccb);
952 FileObject->FsContext = NULL;
953 FileObject->FsContext2 = NULL;
954
955 Irp->IoStatus.Status = STATUS_SUCCESS;
956 Irp->IoStatus.Information = 0;
957 IoCompleteRequest(Irp, IO_NO_INCREMENT);
958 return STATUS_SUCCESS;
959 }
960
961 if (Ccb->Type == CCB_DIRECTORY)
962 {
963 DPRINT("Closing the root directory!\n");
964
965 if (Ccb->u.Directory.SearchPattern.Buffer != NULL)
966 ExFreePoolWithTag(Ccb->u.Directory.SearchPattern.Buffer,
967 TAG_NPFS_NAMEBLOCK);
968
969 NpfsDereferenceCcb(Ccb);
970 FileObject->FsContext = NULL;
971 FileObject->FsContext2 = NULL;
972
973 Irp->IoStatus.Status = STATUS_SUCCESS;
974 Irp->IoStatus.Information = 0;
975 IoCompleteRequest(Irp, IO_NO_INCREMENT);
976 return STATUS_SUCCESS;
977 }
978
979 DPRINT("CCB %p\n", Ccb);
980 Fcb = Ccb->Fcb;
981
982 DPRINT("Closing pipe %wZ\n", &Fcb->PipeName);
983
984 KeLockMutex(&Fcb->CcbListLock);
985
986 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
987
988 if (Server)
989 {
990 DPRINT("Server\n");
991 Fcb->CurrentInstances--;
992 }
993 else
994 {
995 DPRINT("Client\n");
996 }
997
998 /* Disconnect the pipes */
999 if (Ccb->OtherSide)
1000 {
1001 /* FIXME: Timo wants it rewritten */
1002 /*ASSERT(Ccb->OtherSide->OtherSide == Ccb);*/
1003 NpfsCcbSetOtherSide(Ccb->OtherSide, NULL);
1004 NpfsCcbSetOtherSide(Ccb, NULL);
1005 }
1006
1007 ASSERT(Ccb->PipeState == FILE_PIPE_CLOSING_STATE);
1008
1009 FileObject->FsContext2 = NULL;
1010
1011 RemoveEntryList(&Ccb->CcbListEntry);
1012
1013 NpfsDereferenceCcb(Ccb);
1014
1015 KeUnlockMutex(&Fcb->CcbListLock);
1016
1017 NpfsDereferenceFcb(Fcb);
1018 FileObject->FsContext = NULL;
1019
1020 Irp->IoStatus.Status = STATUS_SUCCESS;
1021 Irp->IoStatus.Information = 0;
1022 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1023
1024 DPRINT("Success!\n");
1025
1026 return STATUS_SUCCESS;
1027 }
1028
1029 /* EOF */