3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/fs/np/create.c
6 * PURPOSE: Named pipe filesystem
7 * PROGRAMMER: David Welch <welch@cwcom.net>
10 /* INCLUDES ******************************************************************/
12 #include <ddk/ntddk.h>
19 /* FUNCTIONS *****************************************************************/
22 NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt
,
23 PUNICODE_STRING PipeName
)
25 PLIST_ENTRY CurrentEntry
;
28 CurrentEntry
= DeviceExt
->PipeListHead
.Flink
;
29 while (CurrentEntry
!= &DeviceExt
->PipeListHead
)
31 Pipe
= CONTAINING_RECORD(CurrentEntry
, NPFS_PIPE
, PipeListEntry
);
32 if (RtlCompareUnicodeString(PipeName
,
36 DPRINT("<%wZ> = <%wZ>\n", PipeName
, &Pipe
->PipeName
);
40 CurrentEntry
= CurrentEntry
->Flink
;
48 NpfsFindListeningServerInstance(PNPFS_PIPE Pipe
)
50 PLIST_ENTRY CurrentEntry
;
51 PNPFS_WAITER_ENTRY Waiter
;
54 CurrentEntry
= Pipe
->WaiterListHead
.Flink
;
55 while (CurrentEntry
!= &Pipe
->WaiterListHead
)
57 Waiter
= CONTAINING_RECORD(CurrentEntry
, NPFS_WAITER_ENTRY
, Entry
);
58 if (Waiter
->Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
&&
61 DPRINT("Server found! Fcb %p\n", Waiter
->Fcb
);
63 IoAcquireCancelSpinLock(&oldIrql
);
64 if (!Waiter
->Irp
->Cancel
)
66 IoSetCancelRoutine(Waiter
->Irp
, NULL
);
67 IoReleaseCancelSpinLock(oldIrql
);
70 IoReleaseCancelSpinLock(oldIrql
);
73 CurrentEntry
= CurrentEntry
->Flink
;
81 NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe
,
84 PLIST_ENTRY CurrentEntry
;
85 PNPFS_WAITER_ENTRY Waiter
;
87 CurrentEntry
= Pipe
->WaiterListHead
.Flink
;
88 while (CurrentEntry
!= &Pipe
->WaiterListHead
)
90 Waiter
= CONTAINING_RECORD(CurrentEntry
, NPFS_WAITER_ENTRY
, Entry
);
91 if (Waiter
->Fcb
== Fcb
)
93 DPRINT("Server found! Fcb %p\n", Waiter
->Fcb
);
95 Waiter
->Irp
->IoStatus
.Status
= STATUS_PIPE_CONNECTED
;
96 Waiter
->Irp
->IoStatus
.Information
= 0;
97 IoCompleteRequest(Waiter
->Irp
, IO_NO_INCREMENT
);
99 RemoveEntryList(&Waiter
->Entry
);
103 CurrentEntry
= CurrentEntry
->Flink
;
109 NpfsCreate(PDEVICE_OBJECT DeviceObject
,
112 PIO_STACK_LOCATION IoStack
;
113 PFILE_OBJECT FileObject
;
116 PNPFS_FCB ServerFcb
= NULL
;
117 PNPFS_DEVICE_EXTENSION DeviceExt
;
118 BOOLEAN SpecialAccess
;
120 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
122 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
123 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
124 FileObject
= IoStack
->FileObject
;
125 DPRINT("FileObject %p\n", FileObject
);
126 DPRINT("FileName %wZ\n", &FileObject
->FileName
);
128 Irp
->IoStatus
.Information
= 0;
130 SpecialAccess
= ((IoStack
->Parameters
.Create
.ShareAccess
& 3) == 3);
133 DPRINT("NpfsCreate() open client end for special use!\n");
137 * Step 1. Find the pipe we're trying to open.
139 KeLockMutex(&DeviceExt
->PipeListLock
);
140 Pipe
= NpfsFindPipe(DeviceExt
,
141 &FileObject
->FileName
);
144 /* Not found, bail out with error. */
145 DPRINT("No pipe found!\n");
146 KeUnlockMutex(&DeviceExt
->PipeListLock
);
147 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
148 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
149 return STATUS_OBJECT_NAME_NOT_FOUND
;
152 KeUnlockMutex(&DeviceExt
->PipeListLock
);
155 * Acquire the lock for FCB lists. From now on no modifications to the
156 * FCB lists are allowed, because it can cause various misconsistencies.
158 KeLockMutex(&Pipe
->FcbListLock
);
161 * Step 2. Create the client FCB.
163 ClientFcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
164 if (ClientFcb
== NULL
)
166 DPRINT("No memory!\n");
167 KeUnlockMutex(&Pipe
->FcbListLock
);
168 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
169 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
170 return STATUS_NO_MEMORY
;
173 ClientFcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
174 ClientFcb
->Pipe
= Pipe
;
175 ClientFcb
->PipeEnd
= FILE_PIPE_CLIENT_END
;
176 ClientFcb
->OtherSide
= NULL
;
177 ClientFcb
->PipeState
= SpecialAccess
? 0 : FILE_PIPE_DISCONNECTED_STATE
;
179 /* Initialize data list. */
180 if (Pipe
->OutboundQuota
)
182 ClientFcb
->Data
= ExAllocatePool(PagedPool
, Pipe
->OutboundQuota
);
183 if (ClientFcb
->Data
== NULL
)
185 DPRINT("No memory!\n");
186 ExFreePool(ClientFcb
);
187 KeUnlockMutex(&Pipe
->FcbListLock
);
188 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
189 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
190 return STATUS_NO_MEMORY
;
195 ClientFcb
->Data
= NULL
;
198 ClientFcb
->ReadPtr
= ClientFcb
->Data
;
199 ClientFcb
->WritePtr
= ClientFcb
->Data
;
200 ClientFcb
->ReadDataAvailable
= 0;
201 ClientFcb
->WriteQuotaAvailable
= Pipe
->OutboundQuota
;
202 ClientFcb
->MaxDataLength
= Pipe
->OutboundQuota
;
203 ExInitializeFastMutex(&ClientFcb
->DataListLock
);
204 KeInitializeEvent(&ClientFcb
->ConnectEvent
, SynchronizationEvent
, FALSE
);
205 KeInitializeEvent(&ClientFcb
->Event
, SynchronizationEvent
, FALSE
);
208 * Step 3. Search for listening server FCB.
214 * WARNING: Point of no return! Once we get the server FCB it's
215 * possible that we completed a wait request and so we have to
216 * complete even this request.
219 ServerFcb
= NpfsFindListeningServerInstance(Pipe
);
220 if (ServerFcb
== NULL
)
222 PLIST_ENTRY CurrentEntry
;
226 * If no waiting server FCB was found then try to pick
227 * one of the listing server FCB on the pipe.
230 CurrentEntry
= Pipe
->ServerFcbListHead
.Flink
;
231 while (CurrentEntry
!= &Pipe
->ServerFcbListHead
)
233 Fcb
= CONTAINING_RECORD(CurrentEntry
, NPFS_FCB
, FcbListEntry
);
234 if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
239 CurrentEntry
= CurrentEntry
->Flink
;
243 * No one is listening to me?! I'm so lonely... :(
246 if (ServerFcb
== NULL
)
248 /* Not found, bail out with error for FILE_OPEN requests. */
249 DPRINT("No listening server fcb found!\n");
251 ExFreePool(ClientFcb
->Data
);
252 KeUnlockMutex(&Pipe
->FcbListLock
);
253 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
254 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
255 return STATUS_PIPE_BUSY
;
260 /* Signal the server thread and remove it from the waiter list */
261 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
262 NpfsSignalAndRemoveListeningServerInstance(Pipe
, ServerFcb
);
265 else if (IsListEmpty(&Pipe
->ServerFcbListHead
))
267 DPRINT("No server fcb found!\n");
268 KeUnlockMutex(&Pipe
->FcbListLock
);
269 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
270 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
271 return STATUS_UNSUCCESSFUL
;
275 * Step 4. Add the client FCB to a list and connect it if possible.
278 /* Add the client FCB to the pipe FCB list. */
279 InsertTailList(&Pipe
->ClientFcbListHead
, &ClientFcb
->FcbListEntry
);
281 /* Connect to listening server side */
284 ClientFcb
->OtherSide
= ServerFcb
;
285 ServerFcb
->OtherSide
= ClientFcb
;
286 ClientFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
287 ServerFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
290 KeUnlockMutex(&Pipe
->FcbListLock
);
292 FileObject
->FsContext
= ClientFcb
;
294 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
295 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
297 DPRINT("Success!\n");
299 return STATUS_SUCCESS
;
304 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject
,
307 PIO_STACK_LOCATION IoStack
;
308 PFILE_OBJECT FileObject
;
309 PNPFS_DEVICE_EXTENSION DeviceExt
;
312 PNAMED_PIPE_CREATE_PARAMETERS Buffer
;
313 BOOLEAN NewPipe
= FALSE
;
315 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
317 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
318 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
319 FileObject
= IoStack
->FileObject
;
320 DPRINT("FileObject %p\n", FileObject
);
321 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
323 Buffer
= IoStack
->Parameters
.CreatePipe
.Parameters
;
325 Irp
->IoStatus
.Information
= 0;
327 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
330 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
332 return STATUS_NO_MEMORY
;
335 Fcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
336 KeLockMutex(&DeviceExt
->PipeListLock
);
339 * First search for existing Pipe with the same name.
341 Pipe
= NpfsFindPipe(DeviceExt
,
342 &FileObject
->FileName
);
346 * Found Pipe with the same name. Check if we are
349 KeUnlockMutex(&DeviceExt
->PipeListLock
);
351 if (Pipe
->CurrentInstances
>= Pipe
->MaximumInstances
)
353 DPRINT("Out of instances.\n");
355 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
356 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
357 return STATUS_PIPE_BUSY
;
360 /* FIXME: Check pipe modes also! */
361 if (Pipe
->MaximumInstances
!= Buffer
->MaximumInstances
||
362 Pipe
->TimeOut
.QuadPart
!= Buffer
->DefaultTimeout
.QuadPart
)
364 DPRINT("Asked for invalid pipe mode.\n");
366 Irp
->IoStatus
.Status
= STATUS_ACCESS_DENIED
;
367 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
368 return STATUS_ACCESS_DENIED
;
374 Pipe
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_PIPE
));
377 KeUnlockMutex(&DeviceExt
->PipeListLock
);
378 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
379 Irp
->IoStatus
.Information
= 0;
380 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
381 return STATUS_NO_MEMORY
;
384 if (RtlCreateUnicodeString(&Pipe
->PipeName
, FileObject
->FileName
.Buffer
) == FALSE
)
386 KeUnlockMutex(&DeviceExt
->PipeListLock
);
389 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
390 Irp
->IoStatus
.Information
= 0;
391 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
392 return STATUS_NO_MEMORY
;
395 InitializeListHead(&Pipe
->ServerFcbListHead
);
396 InitializeListHead(&Pipe
->ClientFcbListHead
);
397 InitializeListHead(&Pipe
->WaiterListHead
);
398 KeInitializeMutex(&Pipe
->FcbListLock
, 0);
400 Pipe
->PipeType
= Buffer
->NamedPipeType
;
401 Pipe
->WriteMode
= Buffer
->ReadMode
;
402 Pipe
->ReadMode
= Buffer
->ReadMode
;
403 Pipe
->CompletionMode
= Buffer
->CompletionMode
;
404 Pipe
->PipeConfiguration
= IoStack
->Parameters
.CreatePipe
.Options
& 0x3;
405 Pipe
->MaximumInstances
= Buffer
->MaximumInstances
;
406 Pipe
->CurrentInstances
= 0;
407 Pipe
->TimeOut
= Buffer
->DefaultTimeout
;
408 if (!(IoStack
->Parameters
.Create
.Options
& FILE_PIPE_OUTBOUND
) ||
409 IoStack
->Parameters
.Create
.Options
& FILE_PIPE_FULL_DUPLEX
)
411 if (Buffer
->InboundQuota
== 0)
413 Pipe
->InboundQuota
= DeviceExt
->DefaultQuota
;
417 Pipe
->InboundQuota
= PAGE_ROUND_UP(Buffer
->InboundQuota
);
418 if (Pipe
->InboundQuota
< DeviceExt
->MinQuota
)
420 Pipe
->InboundQuota
= DeviceExt
->MinQuota
;
422 else if (Pipe
->InboundQuota
> DeviceExt
->MaxQuota
)
424 Pipe
->InboundQuota
= DeviceExt
->MaxQuota
;
430 Pipe
->InboundQuota
= 0;
433 if (IoStack
->Parameters
.Create
.Options
& (FILE_PIPE_FULL_DUPLEX
|FILE_PIPE_OUTBOUND
))
435 if (Buffer
->OutboundQuota
== 0)
437 Pipe
->OutboundQuota
= DeviceExt
->DefaultQuota
;
441 Pipe
->OutboundQuota
= PAGE_ROUND_UP(Buffer
->OutboundQuota
);
442 if (Pipe
->OutboundQuota
< DeviceExt
->MinQuota
)
444 Pipe
->OutboundQuota
= DeviceExt
->MinQuota
;
446 else if (Pipe
->OutboundQuota
> DeviceExt
->MaxQuota
)
448 Pipe
->OutboundQuota
= DeviceExt
->MaxQuota
;
454 Pipe
->OutboundQuota
= 0;
457 InsertTailList(&DeviceExt
->PipeListHead
, &Pipe
->PipeListEntry
);
458 KeUnlockMutex(&DeviceExt
->PipeListLock
);
461 if (Pipe
->InboundQuota
)
463 Fcb
->Data
= ExAllocatePool(PagedPool
, Pipe
->InboundQuota
);
464 if (Fcb
->Data
== NULL
)
470 KeLockMutex(&DeviceExt
->PipeListLock
);
471 RemoveEntryList(&Pipe
->PipeListEntry
);
472 KeUnlockMutex(&DeviceExt
->PipeListLock
);
473 RtlFreeUnicodeString(&Pipe
->PipeName
);
477 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
478 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
479 return STATUS_NO_MEMORY
;
487 Fcb
->ReadPtr
= Fcb
->Data
;
488 Fcb
->WritePtr
= Fcb
->Data
;
489 Fcb
->ReadDataAvailable
= 0;
490 Fcb
->WriteQuotaAvailable
= Pipe
->InboundQuota
;
491 Fcb
->MaxDataLength
= Pipe
->InboundQuota
;
492 ExInitializeFastMutex(&Fcb
->DataListLock
);
494 Pipe
->CurrentInstances
++;
497 Fcb
->PipeEnd
= FILE_PIPE_SERVER_END
;
498 Fcb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
499 Fcb
->OtherSide
= NULL
;
501 KeInitializeEvent(&Fcb
->ConnectEvent
,
502 SynchronizationEvent
,
505 KeInitializeEvent(&Fcb
->Event
,
506 SynchronizationEvent
,
509 KeLockMutex(&Pipe
->FcbListLock
);
510 InsertTailList(&Pipe
->ServerFcbListHead
, &Fcb
->FcbListEntry
);
511 KeUnlockMutex(&Pipe
->FcbListLock
);
513 FileObject
->FsContext
= Fcb
;
515 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
516 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
518 DPRINT("Success!\n");
520 return STATUS_SUCCESS
;
525 NpfsCleanup(PDEVICE_OBJECT DeviceObject
,
528 PNPFS_DEVICE_EXTENSION DeviceExt
;
529 PIO_STACK_LOCATION IoStack
;
530 PFILE_OBJECT FileObject
;
535 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
537 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
538 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
539 FileObject
= IoStack
->FileObject
;
540 Fcb
= FileObject
->FsContext
;
544 DPRINT("Success!\n");
545 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
546 Irp
->IoStatus
.Information
= 0;
547 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
548 return STATUS_SUCCESS
;
551 DPRINT("Fcb %x\n", Fcb
);
554 DPRINT("Cleaning pipe %wZ\n", &Pipe
->PipeName
);
556 KeLockMutex(&Pipe
->FcbListLock
);
558 Server
= (Fcb
->PipeEnd
== FILE_PIPE_SERVER_END
);
562 /* FIXME: Clean up existing connections here ?? */
570 if (Fcb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
574 Fcb
->OtherSide
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
575 Fcb
->OtherSide
->OtherSide
= NULL
;
577 * Signaling the write event. If is possible that an other
578 * thread waits for an empty buffer.
580 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
583 else if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
586 PNPFS_WAITER_ENTRY WaitEntry
= NULL
;
587 BOOLEAN Complete
= FALSE
;
590 Entry
= Fcb
->Pipe
->WaiterListHead
.Flink
;
591 while (Entry
!= &Fcb
->Pipe
->WaiterListHead
)
593 WaitEntry
= CONTAINING_RECORD(Entry
, NPFS_WAITER_ENTRY
, Entry
);
594 if (WaitEntry
->Fcb
== Fcb
)
596 RemoveEntryList(Entry
);
597 IoAcquireCancelSpinLock(&oldIrql
);
600 IoSetCancelRoutine(WaitEntry
->Irp
, NULL
);
603 IoReleaseCancelSpinLock(oldIrql
);
606 Entry
= Entry
->Flink
;
609 if (Entry
!= &Fcb
->Pipe
->WaiterListHead
)
613 WaitEntry
->Irp
->IoStatus
.Status
= STATUS_PIPE_BROKEN
;
614 WaitEntry
->Irp
->IoStatus
.Information
= 0;
615 IoCompleteRequest(WaitEntry
->Irp
, IO_NO_INCREMENT
);
617 ExFreePool(WaitEntry
);
620 Fcb
->PipeState
= FILE_PIPE_CLOSING_STATE
;
622 KeUnlockMutex(&Pipe
->FcbListLock
);
624 ExAcquireFastMutex(&Fcb
->DataListLock
);
627 ExFreePool(Fcb
->Data
);
630 Fcb
->WritePtr
= NULL
;
632 ExReleaseFastMutex(&Fcb
->DataListLock
);
634 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
635 Irp
->IoStatus
.Information
= 0;
636 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
638 DPRINT("Success!\n");
640 return STATUS_SUCCESS
;
644 NpfsClose(PDEVICE_OBJECT DeviceObject
,
647 PNPFS_DEVICE_EXTENSION DeviceExt
;
648 PIO_STACK_LOCATION IoStack
;
649 PFILE_OBJECT FileObject
;
654 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
656 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
657 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
658 FileObject
= IoStack
->FileObject
;
659 Fcb
= FileObject
->FsContext
;
663 DPRINT("Success!\n");
664 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
665 Irp
->IoStatus
.Information
= 0;
666 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
667 return STATUS_SUCCESS
;
670 DPRINT("Fcb %x\n", Fcb
);
673 DPRINT("Closing pipe %wZ\n", &Pipe
->PipeName
);
675 KeLockMutex(&Pipe
->FcbListLock
);
677 Server
= (Fcb
->PipeEnd
== FILE_PIPE_SERVER_END
);
682 Pipe
->CurrentInstances
--;
689 ASSERT (Fcb
->PipeState
== FILE_PIPE_CLOSING_STATE
);
691 FileObject
->FsContext
= NULL
;
693 RemoveEntryList(&Fcb
->FcbListEntry
);
697 KeUnlockMutex(&Pipe
->FcbListLock
);
699 if (IsListEmpty(&Pipe
->ServerFcbListHead
) &&
700 IsListEmpty(&Pipe
->ClientFcbListHead
))
702 RtlFreeUnicodeString(&Pipe
->PipeName
);
703 KeLockMutex(&DeviceExt
->PipeListLock
);
704 RemoveEntryList(&Pipe
->PipeListEntry
);
705 KeUnlockMutex(&DeviceExt
->PipeListLock
);
709 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
710 Irp
->IoStatus
.Information
= 0;
711 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
713 DPRINT("Success!\n");
715 return STATUS_SUCCESS
;