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
;
53 CurrentEntry
= Pipe
->WaiterListHead
.Flink
;
54 while (CurrentEntry
!= &Pipe
->WaiterListHead
)
56 Waiter
= CONTAINING_RECORD(CurrentEntry
, NPFS_WAITER_ENTRY
, Entry
);
57 if (Waiter
->Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
59 DPRINT("Server found! Fcb %p\n", Waiter
->Fcb
);
63 CurrentEntry
= CurrentEntry
->Flink
;
71 NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe
,
74 PLIST_ENTRY CurrentEntry
;
75 PNPFS_WAITER_ENTRY Waiter
;
77 CurrentEntry
= Pipe
->WaiterListHead
.Flink
;
78 while (CurrentEntry
!= &Pipe
->WaiterListHead
)
80 Waiter
= CONTAINING_RECORD(CurrentEntry
, NPFS_WAITER_ENTRY
, Entry
);
81 if (Waiter
->Fcb
== Fcb
)
83 DPRINT("Server found! Fcb %p\n", Waiter
->Fcb
);
85 KeSetEvent(Waiter
->Irp
->UserEvent
, 0, FALSE
);
86 Waiter
->Irp
->UserIosb
->Status
= FILE_PIPE_CONNECTED_STATE
;
87 Waiter
->Irp
->UserIosb
->Information
= 0;
88 IoCompleteRequest(Waiter
->Irp
, IO_NO_INCREMENT
);
90 RemoveEntryList(&Waiter
->Entry
);
94 CurrentEntry
= CurrentEntry
->Flink
;
100 NpfsCreate(PDEVICE_OBJECT DeviceObject
,
103 PIO_STACK_LOCATION IoStack
;
104 PFILE_OBJECT FileObject
;
107 PNPFS_FCB ServerFcb
= NULL
;
108 PNPFS_DEVICE_EXTENSION DeviceExt
;
109 BOOLEAN SpecialAccess
;
111 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
113 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
114 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
115 FileObject
= IoStack
->FileObject
;
116 DPRINT("FileObject %p\n", FileObject
);
117 DPRINT("FileName %wZ\n", &FileObject
->FileName
);
119 Irp
->IoStatus
.Information
= 0;
121 SpecialAccess
= ((IoStack
->Parameters
.Create
.ShareAccess
& 3) == 3);
124 DPRINT("NpfsCreate() open client end for special use!\n");
128 * Step 1. Find the pipe we're trying to open.
130 KeLockMutex(&DeviceExt
->PipeListLock
);
131 Pipe
= NpfsFindPipe(DeviceExt
,
132 &FileObject
->FileName
);
135 /* Not found, bail out with error. */
136 DPRINT("No pipe found!\n");
137 KeUnlockMutex(&DeviceExt
->PipeListLock
);
138 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
139 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
140 return STATUS_OBJECT_NAME_NOT_FOUND
;
143 KeUnlockMutex(&DeviceExt
->PipeListLock
);
146 * Step 2. Search for listening server FCB.
150 * Acquire the lock for FCB lists. From now on no modifications to the
151 * FCB lists are allowed, because it can cause various misconsistencies.
153 KeLockMutex(&Pipe
->FcbListLock
);
157 ServerFcb
= NpfsFindListeningServerInstance(Pipe
);
158 if (ServerFcb
== NULL
)
160 /* Not found, bail out with error for FILE_OPEN requests. */
161 DPRINT("No listening server fcb found!\n");
162 KeUnlockMutex(&Pipe
->FcbListLock
);
163 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
164 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
165 return STATUS_PIPE_BUSY
;
168 else if (IsListEmpty(&Pipe
->ServerFcbListHead
))
170 DPRINT("No server fcb found!\n");
171 KeUnlockMutex(&Pipe
->FcbListLock
);
172 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
173 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
174 return STATUS_UNSUCCESSFUL
;
178 * Step 3. Create the client FCB.
180 ClientFcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
181 if (ClientFcb
== NULL
)
183 DPRINT("No memory!\n");
184 KeUnlockMutex(&Pipe
->FcbListLock
);
185 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
186 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
187 return STATUS_NO_MEMORY
;
190 ClientFcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
191 ClientFcb
->Pipe
= Pipe
;
192 ClientFcb
->PipeEnd
= FILE_PIPE_CLIENT_END
;
193 ClientFcb
->OtherSide
= NULL
;
194 ClientFcb
->PipeState
= SpecialAccess
? 0 : FILE_PIPE_DISCONNECTED_STATE
;
196 /* Initialize data list. */
197 if (Pipe
->OutboundQuota
)
199 ClientFcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->OutboundQuota
);
200 if (ClientFcb
->Data
== NULL
)
202 DPRINT("No memory!\n");
203 ExFreePool(ClientFcb
);
204 KeUnlockMutex(&Pipe
->FcbListLock
);
205 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
206 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
207 return STATUS_NO_MEMORY
;
212 ClientFcb
->Data
= NULL
;
215 ClientFcb
->ReadPtr
= ClientFcb
->Data
;
216 ClientFcb
->WritePtr
= ClientFcb
->Data
;
217 ClientFcb
->ReadDataAvailable
= 0;
218 ClientFcb
->WriteQuotaAvailable
= Pipe
->OutboundQuota
;
219 ClientFcb
->MaxDataLength
= Pipe
->OutboundQuota
;
220 KeInitializeSpinLock(&ClientFcb
->DataListLock
);
221 KeInitializeEvent(&ClientFcb
->ConnectEvent
, SynchronizationEvent
, FALSE
);
222 KeInitializeEvent(&ClientFcb
->Event
, SynchronizationEvent
, FALSE
);
225 * Step 4. Add the client FCB to a list and connect it if possible.
228 /* Add the client FCB to the pipe FCB list. */
229 InsertTailList(&Pipe
->ClientFcbListHead
, &ClientFcb
->FcbListEntry
);
231 /* Connect to listening server side */
234 ClientFcb
->OtherSide
= ServerFcb
;
235 ServerFcb
->OtherSide
= ClientFcb
;
236 ClientFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
237 ServerFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
239 /* Signal the server thread and remove it from the waiter list */
240 NpfsSignalAndRemoveListeningServerInstance(Pipe
, ServerFcb
);
243 KeUnlockMutex(&Pipe
->FcbListLock
);
245 FileObject
->FsContext
= ClientFcb
;
247 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
248 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
250 DPRINT("Success!\n");
252 return STATUS_SUCCESS
;
257 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject
,
260 PIO_STACK_LOCATION IoStack
;
261 PFILE_OBJECT FileObject
;
262 PNPFS_DEVICE_EXTENSION DeviceExt
;
265 PNAMED_PIPE_CREATE_PARAMETERS Buffer
;
266 BOOLEAN NewPipe
= FALSE
;
268 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
270 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
271 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
272 FileObject
= IoStack
->FileObject
;
273 DPRINT("FileObject %p\n", FileObject
);
274 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
276 Buffer
= IoStack
->Parameters
.CreatePipe
.Parameters
;
278 Irp
->IoStatus
.Information
= 0;
280 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
283 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
284 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
285 return STATUS_NO_MEMORY
;
288 Fcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
289 KeLockMutex(&DeviceExt
->PipeListLock
);
292 * First search for existing Pipe with the same name.
294 Pipe
= NpfsFindPipe(DeviceExt
,
295 &FileObject
->FileName
);
299 * Found Pipe with the same name. Check if we are
302 KeUnlockMutex(&DeviceExt
->PipeListLock
);
304 if (Pipe
->CurrentInstances
>= Pipe
->MaximumInstances
)
306 DPRINT("Out of instances.\n");
308 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
309 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
310 return STATUS_PIPE_BUSY
;
313 /* FIXME: Check pipe modes also! */
314 if (Pipe
->MaximumInstances
!= Buffer
->MaximumInstances
||
315 Pipe
->TimeOut
.QuadPart
!= Buffer
->DefaultTimeout
.QuadPart
)
317 DPRINT("Asked for invalid pipe mode.\n");
319 Irp
->IoStatus
.Status
= STATUS_ACCESS_DENIED
;
320 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
321 return STATUS_ACCESS_DENIED
;
327 Pipe
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_PIPE
));
330 KeUnlockMutex(&DeviceExt
->PipeListLock
);
331 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
332 Irp
->IoStatus
.Information
= 0;
333 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
334 return STATUS_NO_MEMORY
;
337 if (RtlCreateUnicodeString(&Pipe
->PipeName
, FileObject
->FileName
.Buffer
) == FALSE
)
339 KeUnlockMutex(&DeviceExt
->PipeListLock
);
342 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
343 Irp
->IoStatus
.Information
= 0;
344 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
345 return STATUS_NO_MEMORY
;
348 InitializeListHead(&Pipe
->ServerFcbListHead
);
349 InitializeListHead(&Pipe
->ClientFcbListHead
);
350 InitializeListHead(&Pipe
->WaiterListHead
);
351 KeInitializeMutex(&Pipe
->FcbListLock
, 0);
353 Pipe
->PipeType
= Buffer
->NamedPipeType
;
354 Pipe
->WriteMode
= Buffer
->ReadMode
;
355 Pipe
->ReadMode
= Buffer
->ReadMode
;
356 Pipe
->CompletionMode
= Buffer
->CompletionMode
;
357 Pipe
->PipeConfiguration
= IoStack
->Parameters
.CreatePipe
.Options
& 0x3;
358 Pipe
->MaximumInstances
= Buffer
->MaximumInstances
;
359 Pipe
->CurrentInstances
= 0;
360 Pipe
->TimeOut
= Buffer
->DefaultTimeout
;
361 if (!(IoStack
->Parameters
.Create
.Options
& FILE_PIPE_OUTBOUND
) ||
362 IoStack
->Parameters
.Create
.Options
& FILE_PIPE_FULL_DUPLEX
)
364 if (Buffer
->InboundQuota
== 0)
366 Pipe
->InboundQuota
= DeviceExt
->DefaultQuota
;
370 Pipe
->InboundQuota
= PAGE_ROUND_UP(Buffer
->InboundQuota
);
371 if (Pipe
->InboundQuota
< DeviceExt
->MinQuota
)
373 Pipe
->InboundQuota
= DeviceExt
->MinQuota
;
375 else if (Pipe
->InboundQuota
> DeviceExt
->MaxQuota
)
377 Pipe
->InboundQuota
= DeviceExt
->MaxQuota
;
383 Pipe
->InboundQuota
= 0;
386 if (IoStack
->Parameters
.Create
.Options
& (FILE_PIPE_FULL_DUPLEX
|FILE_PIPE_OUTBOUND
))
388 if (Buffer
->OutboundQuota
== 0)
390 Pipe
->OutboundQuota
= DeviceExt
->DefaultQuota
;
394 Pipe
->OutboundQuota
= PAGE_ROUND_UP(Buffer
->OutboundQuota
);
395 if (Pipe
->OutboundQuota
< DeviceExt
->MinQuota
)
397 Pipe
->OutboundQuota
= DeviceExt
->MinQuota
;
399 else if (Pipe
->OutboundQuota
> DeviceExt
->MaxQuota
)
401 Pipe
->OutboundQuota
= DeviceExt
->MaxQuota
;
407 Pipe
->OutboundQuota
= 0;
410 InsertTailList(&DeviceExt
->PipeListHead
, &Pipe
->PipeListEntry
);
411 KeUnlockMutex(&DeviceExt
->PipeListLock
);
414 if (Pipe
->InboundQuota
)
416 Fcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->InboundQuota
);
417 if (Fcb
->Data
== NULL
)
423 RtlFreeUnicodeString(&Pipe
->PipeName
);
427 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
428 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
429 return STATUS_NO_MEMORY
;
437 Fcb
->ReadPtr
= Fcb
->Data
;
438 Fcb
->WritePtr
= Fcb
->Data
;
439 Fcb
->ReadDataAvailable
= 0;
440 Fcb
->WriteQuotaAvailable
= Pipe
->InboundQuota
;
441 Fcb
->MaxDataLength
= Pipe
->InboundQuota
;
442 KeInitializeSpinLock(&Fcb
->DataListLock
);
444 Pipe
->CurrentInstances
++;
446 KeLockMutex(&Pipe
->FcbListLock
);
447 InsertTailList(&Pipe
->ServerFcbListHead
, &Fcb
->FcbListEntry
);
448 KeUnlockMutex(&Pipe
->FcbListLock
);
451 Fcb
->PipeEnd
= FILE_PIPE_SERVER_END
;
452 Fcb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
453 Fcb
->OtherSide
= NULL
;
455 KeInitializeEvent(&Fcb
->ConnectEvent
,
456 SynchronizationEvent
,
459 KeInitializeEvent(&Fcb
->Event
,
460 SynchronizationEvent
,
463 FileObject
->FsContext
= Fcb
;
465 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
466 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
468 DPRINT("Success!\n");
470 return STATUS_SUCCESS
;
475 NpfsClose(PDEVICE_OBJECT DeviceObject
,
478 PNPFS_DEVICE_EXTENSION DeviceExt
;
479 PIO_STACK_LOCATION IoStack
;
480 PFILE_OBJECT FileObject
;
485 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
487 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
488 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
489 FileObject
= IoStack
->FileObject
;
490 Fcb
= FileObject
->FsContext
;
494 DPRINT("Success!\n");
495 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
496 Irp
->IoStatus
.Information
= 0;
497 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
498 return STATUS_SUCCESS
;
501 DPRINT("Fcb %x\n", Fcb
);
504 DPRINT("Closing pipe %wZ\n", &Pipe
->PipeName
);
506 KeLockMutex(&Pipe
->FcbListLock
);
508 Server
= (Fcb
->PipeEnd
== FILE_PIPE_SERVER_END
);
512 /* FIXME: Clean up existing connections here ?? */
514 Pipe
->CurrentInstances
--;
521 if (Fcb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
525 Fcb
->OtherSide
->PipeState
= FILE_PIPE_CLOSING_STATE
;
526 Fcb
->OtherSide
->OtherSide
= NULL
;
528 * Signaling the write event. If is possible that an other
529 * thread waits for an empty buffer.
531 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
537 FileObject
->FsContext
= NULL
;
539 RemoveEntryList(&Fcb
->FcbListEntry
);
541 ExFreePool(Fcb
->Data
);
544 KeUnlockMutex(&Pipe
->FcbListLock
);
546 if (IsListEmpty(&Pipe
->ServerFcbListHead
) &&
547 IsListEmpty(&Pipe
->ClientFcbListHead
))
549 RtlFreeUnicodeString(&Pipe
->PipeName
);
550 KeLockMutex(&DeviceExt
->PipeListLock
);
551 RemoveEntryList(&Pipe
->PipeListEntry
);
552 KeUnlockMutex(&DeviceExt
->PipeListLock
);
556 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
557 Irp
->IoStatus
.Information
= 0;
558 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
560 DPRINT("Success!\n");
562 return STATUS_SUCCESS
;