3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/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
;
53 CurrentEntry
= Pipe
->ServerFcbListHead
.Flink
;
54 while (CurrentEntry
!= &Pipe
->ServerFcbListHead
)
56 ServerFcb
= CONTAINING_RECORD(CurrentEntry
, NPFS_FCB
, FcbListEntry
);
57 if (ServerFcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
59 DPRINT("Server found! Fcb %p\n", ServerFcb
);
62 CurrentEntry
= CurrentEntry
->Flink
;
70 NpfsCreate(PDEVICE_OBJECT DeviceObject
,
73 PIO_STACK_LOCATION IoStack
;
74 PFILE_OBJECT FileObject
;
77 PNPFS_FCB ServerFcb
= NULL
;
78 PNPFS_DEVICE_EXTENSION DeviceExt
;
79 BOOLEAN SpecialAccess
;
81 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
83 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
84 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
85 FileObject
= IoStack
->FileObject
;
86 DPRINT("FileObject %p\n", FileObject
);
87 DPRINT("FileName %wZ\n", &FileObject
->FileName
);
89 Irp
->IoStatus
.Information
= 0;
91 SpecialAccess
= ((IoStack
->Parameters
.Create
.ShareAccess
& 3) == 3);
94 DPRINT("NpfsCreate() open client end for special use!\n");
98 * Step 1. Find the pipe we're trying to open.
100 KeLockMutex(&DeviceExt
->PipeListLock
);
101 Pipe
= NpfsFindPipe(DeviceExt
,
102 &FileObject
->FileName
);
105 /* Not found, bail out with error. */
106 DPRINT("No pipe found!\n");
107 KeUnlockMutex(&DeviceExt
->PipeListLock
);
108 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
109 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
110 return STATUS_OBJECT_NAME_NOT_FOUND
;
113 KeUnlockMutex(&DeviceExt
->PipeListLock
);
116 * Step 2. Search for listening server FCB.
120 * Acquire the lock for FCB lists. From now on no modifications to the
121 * FCB lists are allowed, because it can cause various misconsistencies.
123 KeLockMutex(&Pipe
->FcbListLock
);
127 ServerFcb
= NpfsFindListeningServerInstance(Pipe
);
128 if (ServerFcb
== NULL
)
130 /* Not found, bail out with error for FILE_OPEN requests. */
131 DPRINT("No listening server fcb found!\n");
132 KeUnlockMutex(&Pipe
->FcbListLock
);
133 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
134 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
135 return STATUS_PIPE_BUSY
;
138 else if (IsListEmpty(&Pipe
->ServerFcbListHead
))
140 DPRINT("No server fcb found!\n");
141 KeUnlockMutex(&Pipe
->FcbListLock
);
142 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
143 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
144 return STATUS_UNSUCCESSFUL
;
148 * Step 3. Create the client FCB.
150 ClientFcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
151 if (ClientFcb
== NULL
)
153 DPRINT("No memory!\n");
154 KeUnlockMutex(&Pipe
->FcbListLock
);
155 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
156 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
157 return STATUS_NO_MEMORY
;
160 ClientFcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
161 ClientFcb
->Pipe
= Pipe
;
162 ClientFcb
->PipeEnd
= FILE_PIPE_CLIENT_END
;
163 ClientFcb
->OtherSide
= NULL
;
164 ClientFcb
->PipeState
= SpecialAccess
? 0 : FILE_PIPE_DISCONNECTED_STATE
;
166 /* Initialize data list. */
167 if (Pipe
->InboundQuota
)
169 ClientFcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->InboundQuota
);
170 if (ClientFcb
->Data
== NULL
)
172 DPRINT("No memory!\n");
173 ExFreePool(ClientFcb
);
174 KeUnlockMutex(&Pipe
->FcbListLock
);
175 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
176 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
177 return STATUS_NO_MEMORY
;
182 ClientFcb
->Data
= NULL
;
185 ClientFcb
->ReadPtr
= ClientFcb
->Data
;
186 ClientFcb
->WritePtr
= ClientFcb
->Data
;
187 ClientFcb
->ReadDataAvailable
= 0;
188 ClientFcb
->WriteQuotaAvailable
= Pipe
->InboundQuota
;
189 ClientFcb
->MaxDataLength
= Pipe
->InboundQuota
;
190 KeInitializeSpinLock(&ClientFcb
->DataListLock
);
191 KeInitializeEvent(&ClientFcb
->ConnectEvent
, SynchronizationEvent
, FALSE
);
192 KeInitializeEvent(&ClientFcb
->Event
, SynchronizationEvent
, FALSE
);
195 * Step 4. Add the client FCB to a list and connect it if necessary.
198 /* Add the client FCB to the pipe FCB list. */
199 InsertTailList(&Pipe
->ClientFcbListHead
, &ClientFcb
->FcbListEntry
);
201 /* Connect pipes if they were created by the same thread */
202 if (ServerFcb
&& ServerFcb
->Thread
== ClientFcb
->Thread
)
204 ClientFcb
->OtherSide
= ServerFcb
;
205 ServerFcb
->OtherSide
= ClientFcb
;
206 ClientFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
207 ServerFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
209 /* Wake server thread */
210 DPRINT("Setting the ConnectEvent for %x\n", ServerFcb
);
211 KeSetEvent(&ServerFcb
->ConnectEvent
, 0, FALSE
);
214 KeUnlockMutex(&Pipe
->FcbListLock
);
216 FileObject
->FsContext
= ClientFcb
;
218 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
219 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
221 DPRINT("Success!\n");
223 return STATUS_SUCCESS
;
228 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject
,
231 PIO_STACK_LOCATION IoStack
;
232 PFILE_OBJECT FileObject
;
233 PNPFS_DEVICE_EXTENSION DeviceExt
;
236 PNAMED_PIPE_CREATE_PARAMETERS Buffer
;
237 BOOLEAN NewPipe
= FALSE
;
239 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
241 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
242 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
243 FileObject
= IoStack
->FileObject
;
244 DPRINT("FileObject %p\n", FileObject
);
245 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
247 Buffer
= IoStack
->Parameters
.CreatePipe
.Parameters
;
249 Irp
->IoStatus
.Information
= 0;
251 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
254 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
255 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
256 return STATUS_NO_MEMORY
;
259 Fcb
->Thread
= (struct ETHREAD
*)Irp
->Tail
.Overlay
.Thread
;
260 KeLockMutex(&DeviceExt
->PipeListLock
);
263 * First search for existing Pipe with the same name.
265 Pipe
= NpfsFindPipe(DeviceExt
,
266 &FileObject
->FileName
);
270 * Found Pipe with the same name. Check if we are
273 KeUnlockMutex(&DeviceExt
->PipeListLock
);
275 if (Pipe
->CurrentInstances
>= Pipe
->MaximumInstances
)
277 DPRINT("Out of instances.\n");
279 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
280 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
281 return STATUS_PIPE_BUSY
;
284 /* FIXME: Check pipe modes also! */
285 if (Pipe
->MaximumInstances
!= Buffer
->MaximumInstances
||
286 Pipe
->TimeOut
.QuadPart
!= Buffer
->DefaultTimeout
.QuadPart
)
288 DPRINT("Asked for invalid pipe mode.\n");
290 Irp
->IoStatus
.Status
= STATUS_ACCESS_DENIED
;
291 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
292 return STATUS_ACCESS_DENIED
;
298 Pipe
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_PIPE
));
301 KeUnlockMutex(&DeviceExt
->PipeListLock
);
302 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
303 Irp
->IoStatus
.Information
= 0;
304 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
305 return STATUS_NO_MEMORY
;
308 if (RtlCreateUnicodeString(&Pipe
->PipeName
, FileObject
->FileName
.Buffer
) == FALSE
)
310 KeUnlockMutex(&DeviceExt
->PipeListLock
);
313 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
314 Irp
->IoStatus
.Information
= 0;
315 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
316 return STATUS_NO_MEMORY
;
319 InitializeListHead(&Pipe
->ServerFcbListHead
);
320 InitializeListHead(&Pipe
->ClientFcbListHead
);
321 KeInitializeMutex(&Pipe
->FcbListLock
, 0);
323 Pipe
->PipeType
= Buffer
->NamedPipeType
? FILE_PIPE_MESSAGE_TYPE
: FILE_PIPE_BYTE_STREAM_TYPE
;
324 Pipe
->PipeWriteMode
= Buffer
->NamedPipeType
? FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
325 Pipe
->PipeReadMode
= Buffer
->ReadMode
? FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
326 Pipe
->PipeBlockMode
= Buffer
->CompletionMode
;
327 Pipe
->PipeConfiguration
= IoStack
->Parameters
.Create
.Options
& 0x3;
328 Pipe
->MaximumInstances
= Buffer
->MaximumInstances
;
329 Pipe
->CurrentInstances
= 0;
330 Pipe
->TimeOut
= Buffer
->DefaultTimeout
;
331 if (!(IoStack
->Parameters
.Create
.Options
& FILE_PIPE_OUTBOUND
) ||
332 IoStack
->Parameters
.Create
.Options
& FILE_PIPE_FULL_DUPLEX
)
334 if (Buffer
->InboundQuota
== 0)
336 Pipe
->InboundQuota
= DeviceExt
->DefaultQuota
;
340 Pipe
->InboundQuota
= PAGE_ROUND_UP(Buffer
->InboundQuota
);
341 if (Pipe
->InboundQuota
< DeviceExt
->MinQuota
)
343 Pipe
->InboundQuota
= DeviceExt
->MinQuota
;
345 else if (Pipe
->InboundQuota
> DeviceExt
->MaxQuota
)
347 Pipe
->InboundQuota
= DeviceExt
->MaxQuota
;
353 Pipe
->InboundQuota
= 0;
356 if (IoStack
->Parameters
.Create
.Options
& (FILE_PIPE_FULL_DUPLEX
|FILE_PIPE_OUTBOUND
))
358 if (Buffer
->OutboundQuota
== 0)
360 Pipe
->OutboundQuota
= DeviceExt
->DefaultQuota
;
364 Pipe
->OutboundQuota
= PAGE_ROUND_UP(Buffer
->OutboundQuota
);
365 if (Pipe
->OutboundQuota
< DeviceExt
->MinQuota
)
367 Pipe
->OutboundQuota
= DeviceExt
->MinQuota
;
369 else if (Pipe
->OutboundQuota
> DeviceExt
->MaxQuota
)
371 Pipe
->OutboundQuota
= DeviceExt
->MaxQuota
;
377 Pipe
->OutboundQuota
= 0;
380 InsertTailList(&DeviceExt
->PipeListHead
, &Pipe
->PipeListEntry
);
381 KeUnlockMutex(&DeviceExt
->PipeListLock
);
384 if (Pipe
->OutboundQuota
)
386 Fcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->OutboundQuota
);
387 if (Fcb
->Data
== NULL
)
393 RtlFreeUnicodeString(&Pipe
->PipeName
);
397 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
398 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
399 return STATUS_NO_MEMORY
;
407 Fcb
->ReadPtr
= Fcb
->Data
;
408 Fcb
->WritePtr
= Fcb
->Data
;
409 Fcb
->ReadDataAvailable
= 0;
410 Fcb
->WriteQuotaAvailable
= Pipe
->OutboundQuota
;
411 Fcb
->MaxDataLength
= Pipe
->OutboundQuota
;
412 KeInitializeSpinLock(&Fcb
->DataListLock
);
414 Pipe
->CurrentInstances
++;
416 KeLockMutex(&Pipe
->FcbListLock
);
417 InsertTailList(&Pipe
->ServerFcbListHead
, &Fcb
->FcbListEntry
);
418 KeUnlockMutex(&Pipe
->FcbListLock
);
421 Fcb
->PipeEnd
= FILE_PIPE_SERVER_END
;
422 Fcb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
423 Fcb
->OtherSide
= NULL
;
425 KeInitializeEvent(&Fcb
->ConnectEvent
,
426 SynchronizationEvent
,
429 KeInitializeEvent(&Fcb
->Event
,
430 SynchronizationEvent
,
433 FileObject
->FsContext
= Fcb
;
435 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
436 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
438 DPRINT("Success!\n");
440 return STATUS_SUCCESS
;
446 PDEVICE_OBJECT DeviceObject
,
449 PNPFS_DEVICE_EXTENSION DeviceExt
;
450 PIO_STACK_LOCATION IoStack
;
451 PFILE_OBJECT FileObject
;
456 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
458 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
459 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
460 FileObject
= IoStack
->FileObject
;
461 Fcb
= FileObject
->FsContext
;
465 DPRINT("Success!\n");
466 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
467 Irp
->IoStatus
.Information
= 0;
468 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
469 return STATUS_SUCCESS
;
472 DPRINT("Fcb %x\n", Fcb
);
475 DPRINT("Closing pipe %wZ\n", &Pipe
->PipeName
);
477 KeLockMutex(&Pipe
->FcbListLock
);
479 Server
= (Fcb
->PipeEnd
== FILE_PIPE_SERVER_END
);
483 /* FIXME: Clean up existing connections here ?? */
485 Pipe
->CurrentInstances
--;
492 if (Fcb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
496 #ifndef FIN_WORKAROUND_READCLOSE
497 Fcb
->OtherSide
->PipeState
= FILE_PIPE_CLOSING_STATE
;
498 Fcb
->OtherSide
->OtherSide
= NULL
;
501 * Signaling the write event. If is possible that an other
502 * thread waits for an empty buffer.
504 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
507 #ifndef FIN_WORKAROUND_READCLOSE
512 FileObject
->FsContext
= NULL
;
514 #ifndef FIN_WORKAROUND_READCLOSE
515 RemoveEntryList(&Fcb
->FcbListEntry
);
517 ExFreePool(Fcb
->Data
);
520 Fcb
->PipeState
= FILE_PIPE_CLOSING_STATE
;
521 if (Fcb
->OtherSide
== NULL
||
522 Fcb
->OtherSide
->PipeState
== FILE_PIPE_CLOSING_STATE
)
524 if (Server
&& Fcb
->OtherSide
!= NULL
&&
525 Fcb
->OtherSide
->PipeState
== FILE_PIPE_CLOSING_STATE
)
527 RemoveEntryList(&Fcb
->OtherSide
->FcbListEntry
);
528 if (Fcb
->OtherSide
->Data
)
529 ExFreePool(Fcb
->OtherSide
->Data
);
530 ExFreePool(Fcb
->OtherSide
);
533 RemoveEntryList(&Fcb
->FcbListEntry
);
535 ExFreePool(Fcb
->Data
);
541 KeUnlockMutex(&Pipe
->FcbListLock
);
543 if (IsListEmpty(&Pipe
->ServerFcbListHead
) &&
544 IsListEmpty(&Pipe
->ClientFcbListHead
))
546 RtlFreeUnicodeString(&Pipe
->PipeName
);
547 KeLockMutex(&DeviceExt
->PipeListLock
);
548 RemoveEntryList(&Pipe
->PipeListEntry
);
549 KeUnlockMutex(&DeviceExt
->PipeListLock
);
553 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
554 Irp
->IoStatus
.Information
= 0;
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
557 DPRINT("Success!\n");
559 return STATUS_SUCCESS
;