1 /* $Id: create.c,v 1.19 2004/05/05 18:30:16 navaraf Exp $
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 *****************************************************************/
23 PDEVICE_OBJECT DeviceObject
,
26 PLIST_ENTRY CurrentEntry
;
28 PIO_STACK_LOCATION IoStack
;
29 PFILE_OBJECT FileObject
;
33 PNPFS_DEVICE_EXTENSION DeviceExt
;
36 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
38 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
39 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
40 FileObject
= IoStack
->FileObject
;
41 Disposition
= ((IoStack
->Parameters
.Create
.Options
>> 24) & 0xff);
42 DPRINT("FileObject %p\n", FileObject
);
43 DPRINT("FileName %wZ\n", &FileObject
->FileName
);
45 Irp
->IoStatus
.Information
= 0;
48 * Step 1. Find the pipe we're trying to open.
51 KeLockMutex(&DeviceExt
->PipeListLock
);
52 CurrentEntry
= DeviceExt
->PipeListHead
.Flink
;
53 while (CurrentEntry
!= &DeviceExt
->PipeListHead
)
55 Current
= CONTAINING_RECORD(CurrentEntry
, NPFS_PIPE
, PipeListEntry
);
56 if (RtlCompareUnicodeString(
57 &FileObject
->FileName
,
63 CurrentEntry
= CurrentEntry
->Flink
;
66 /* Not found, bail out with error. */
67 if (CurrentEntry
== &DeviceExt
->PipeListHead
)
69 DPRINT("No pipe found!\n");
70 KeUnlockMutex(&DeviceExt
->PipeListLock
);
71 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
72 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
73 return STATUS_OBJECT_NAME_NOT_FOUND
;
76 KeUnlockMutex(&DeviceExt
->PipeListLock
);
78 /* Save the pipe we found for later use. */
82 * Step 2. Search for listening server FCB.
86 * Acquire the lock for FCB lists. From now on no modifications to the
87 * FCB lists are allowed, because it can cause various misconsistencies.
89 KeLockMutex(&Pipe
->FcbListLock
);
91 CurrentEntry
= Pipe
->ServerFcbListHead
.Flink
;
92 while (CurrentEntry
!= &Pipe
->ServerFcbListHead
)
94 ServerFcb
= CONTAINING_RECORD(CurrentEntry
, NPFS_FCB
, FcbListEntry
);
95 if (ServerFcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
97 DPRINT("Server found! Fcb %p\n", ServerFcb
);
100 CurrentEntry
= CurrentEntry
->Flink
;
103 /* Not found, bail out with error for FILE_OPEN requests. */
104 if (CurrentEntry
== &Pipe
->ServerFcbListHead
)
106 DPRINT("No server fcb found!\n");
107 if (Disposition
== FILE_OPEN
)
109 KeUnlockMutex(&Pipe
->FcbListLock
);
110 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
111 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
112 return STATUS_PIPE_BUSY
;
118 * Step 3. Create the client FCB.
121 ClientFcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
122 if (ClientFcb
== NULL
)
124 DPRINT("No memory!\n");
125 KeUnlockMutex(&Pipe
->FcbListLock
);
126 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
127 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
128 return STATUS_NO_MEMORY
;
131 ClientFcb
->Pipe
= Pipe
;
132 ClientFcb
->PipeEnd
= FILE_PIPE_CLIENT_END
;
133 ClientFcb
->OtherSide
= NULL
;
134 ClientFcb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
136 /* Initialize data list. */
137 if (Pipe
->InboundQuota
)
139 ClientFcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->InboundQuota
);
140 if (ClientFcb
->Data
== NULL
)
142 DPRINT("No memory!\n");
143 ExFreePool(ClientFcb
);
144 KeUnlockMutex(&Pipe
->FcbListLock
);
145 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
146 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
147 return STATUS_NO_MEMORY
;
152 ClientFcb
->Data
= NULL
;
155 ClientFcb
->ReadPtr
= ClientFcb
->Data
;
156 ClientFcb
->WritePtr
= ClientFcb
->Data
;
157 ClientFcb
->ReadDataAvailable
= 0;
158 ClientFcb
->WriteQuotaAvailable
= Pipe
->InboundQuota
;
159 ClientFcb
->MaxDataLength
= Pipe
->InboundQuota
;
160 KeInitializeSpinLock(&ClientFcb
->DataListLock
);
161 KeInitializeEvent(&ClientFcb
->ConnectEvent
, SynchronizationEvent
, FALSE
);
162 KeInitializeEvent(&ClientFcb
->Event
, SynchronizationEvent
, FALSE
);
165 * Step 4. Add the client FCB to a list and connect it if necessary.
168 /* Add the client FCB to the pipe FCB list. */
169 InsertTailList(&Pipe
->ClientFcbListHead
, &ClientFcb
->FcbListEntry
);
173 ClientFcb
->OtherSide
= ServerFcb
;
174 ServerFcb
->OtherSide
= ClientFcb
;
175 ClientFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
176 ServerFcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
178 /* Wake server thread */
179 DPRINT("Setting the ConnectEvent for %x\n", ServerFcb
);
180 KeSetEvent(&ServerFcb
->ConnectEvent
, 0, FALSE
);
183 KeUnlockMutex(&Pipe
->FcbListLock
);
185 FileObject
->FsContext
= ClientFcb
;
187 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
188 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
190 DPRINT("Success!\n");
192 return STATUS_SUCCESS
;
197 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject
,
200 PIO_STACK_LOCATION IoStack
;
201 PFILE_OBJECT FileObject
;
202 PNPFS_DEVICE_EXTENSION DeviceExt
;
205 PLIST_ENTRY current_entry
;
207 PIO_PIPE_CREATE_BUFFER Buffer
;
209 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
211 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
212 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
213 FileObject
= IoStack
->FileObject
;
214 DPRINT("FileObject %p\n", FileObject
);
215 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
217 Buffer
= (PIO_PIPE_CREATE_BUFFER
)Irp
->Tail
.Overlay
.AuxiliaryBuffer
;
219 Irp
->IoStatus
.Information
= 0;
221 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_FCB
));
224 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
225 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
226 return STATUS_NO_MEMORY
;
229 KeLockMutex(&DeviceExt
->PipeListLock
);
232 * First search for existing Pipe with the same name.
235 current_entry
= DeviceExt
->PipeListHead
.Flink
;
236 while (current_entry
!= &DeviceExt
->PipeListHead
)
238 current
= CONTAINING_RECORD(current_entry
,
242 if (RtlCompareUnicodeString(&FileObject
->FileName
, ¤t
->PipeName
, TRUE
) == 0)
247 current_entry
= current_entry
->Flink
;
250 if (current_entry
!= &DeviceExt
->PipeListHead
)
253 * Found Pipe with the same name. Check if we are
258 KeUnlockMutex(&DeviceExt
->PipeListLock
);
260 if (Pipe
->CurrentInstances
>= Pipe
->MaximumInstances
)
262 DPRINT("Out of instances.\n");
264 Irp
->IoStatus
.Status
= STATUS_PIPE_BUSY
;
265 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
266 return STATUS_PIPE_BUSY
;
269 /* FIXME: Check pipe modes also! */
270 if (Pipe
->MaximumInstances
!= Buffer
->MaxInstances
||
271 Pipe
->TimeOut
.QuadPart
!= Buffer
->TimeOut
.QuadPart
)
273 DPRINT("Asked for invalid pipe mode.\n");
275 Irp
->IoStatus
.Status
= STATUS_ACCESS_DENIED
;
276 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
277 return STATUS_ACCESS_DENIED
;
282 Pipe
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_PIPE
));
285 KeUnlockMutex(&DeviceExt
->PipeListLock
);
286 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
287 Irp
->IoStatus
.Information
= 0;
288 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
289 return STATUS_NO_MEMORY
;
292 if (RtlCreateUnicodeString(&Pipe
->PipeName
, FileObject
->FileName
.Buffer
) == 0)
294 KeUnlockMutex(&DeviceExt
->PipeListLock
);
297 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
298 Irp
->IoStatus
.Information
= 0;
299 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
300 return(STATUS_NO_MEMORY
);
303 InitializeListHead(&Pipe
->ServerFcbListHead
);
304 InitializeListHead(&Pipe
->ClientFcbListHead
);
305 KeInitializeMutex(&Pipe
->FcbListLock
, 0);
307 Pipe
->PipeType
= Buffer
->WriteModeMessage
? FILE_PIPE_MESSAGE_TYPE
: FILE_PIPE_BYTE_STREAM_TYPE
;
308 Pipe
->PipeWriteMode
= Buffer
->WriteModeMessage
? FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
309 Pipe
->PipeReadMode
= Buffer
->ReadModeMessage
? FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
310 Pipe
->PipeBlockMode
= Buffer
->NonBlocking
;
311 Pipe
->PipeConfiguration
= IoStack
->Parameters
.Create
.Options
& 0x3;
312 Pipe
->MaximumInstances
= Buffer
->MaxInstances
;
313 Pipe
->CurrentInstances
= 0;
314 Pipe
->TimeOut
= Buffer
->TimeOut
;
315 if (!(IoStack
->Parameters
.Create
.Options
& FILE_PIPE_OUTBOUND
) ||
316 IoStack
->Parameters
.Create
.Options
& FILE_PIPE_FULL_DUPLEX
)
318 if (Buffer
->InBufferSize
== 0)
320 Pipe
->InboundQuota
= DeviceExt
->DefaultQuota
;
324 Pipe
->InboundQuota
= PAGE_ROUND_UP(Buffer
->InBufferSize
);
325 if (Pipe
->InboundQuota
< DeviceExt
->MinQuota
)
327 Pipe
->InboundQuota
= DeviceExt
->MinQuota
;
329 else if (Pipe
->InboundQuota
> DeviceExt
->MaxQuota
)
331 Pipe
->InboundQuota
= DeviceExt
->MaxQuota
;
337 Pipe
->InboundQuota
= 0;
339 if (IoStack
->Parameters
.Create
.Options
& (FILE_PIPE_FULL_DUPLEX
|FILE_PIPE_OUTBOUND
))
341 if (Buffer
->OutBufferSize
== 0)
343 Pipe
->OutboundQuota
= DeviceExt
->DefaultQuota
;
347 Pipe
->OutboundQuota
= PAGE_ROUND_UP(Buffer
->OutBufferSize
);
348 if (Pipe
->OutboundQuota
< DeviceExt
->MinQuota
)
350 Pipe
->OutboundQuota
= DeviceExt
->MinQuota
;
352 else if (Pipe
->OutboundQuota
> DeviceExt
->MaxQuota
)
354 Pipe
->OutboundQuota
= DeviceExt
->MaxQuota
;
360 Pipe
->OutboundQuota
= 0;
363 InsertTailList(&DeviceExt
->PipeListHead
, &Pipe
->PipeListEntry
);
364 KeUnlockMutex(&DeviceExt
->PipeListLock
);
367 if (Pipe
->OutboundQuota
)
369 Fcb
->Data
= ExAllocatePool(NonPagedPool
, Pipe
->OutboundQuota
);
370 if (Fcb
->Data
== NULL
)
376 RtlFreeUnicodeString(&Pipe
->PipeName
);
380 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
381 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
382 return STATUS_NO_MEMORY
;
390 Fcb
->ReadPtr
= Fcb
->Data
;
391 Fcb
->WritePtr
= Fcb
->Data
;
392 Fcb
->ReadDataAvailable
= 0;
393 Fcb
->WriteQuotaAvailable
= Pipe
->OutboundQuota
;
394 Fcb
->MaxDataLength
= Pipe
->OutboundQuota
;
395 KeInitializeSpinLock(&Fcb
->DataListLock
);
397 Pipe
->CurrentInstances
++;
399 KeLockMutex(&Pipe
->FcbListLock
);
400 InsertTailList(&Pipe
->ServerFcbListHead
, &Fcb
->FcbListEntry
);
401 KeUnlockMutex(&Pipe
->FcbListLock
);
404 Fcb
->PipeEnd
= FILE_PIPE_SERVER_END
;
405 Fcb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
406 Fcb
->OtherSide
= NULL
;
408 KeInitializeEvent(&Fcb
->ConnectEvent
,
409 SynchronizationEvent
,
412 KeInitializeEvent(&Fcb
->Event
,
413 SynchronizationEvent
,
416 FileObject
->FsContext
= Fcb
;
418 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
419 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
421 return(STATUS_SUCCESS
);
427 PDEVICE_OBJECT DeviceObject
,
430 PNPFS_DEVICE_EXTENSION DeviceExt
;
431 PIO_STACK_LOCATION IoStack
;
432 PFILE_OBJECT FileObject
;
437 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
439 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
440 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
441 FileObject
= IoStack
->FileObject
;
442 Fcb
= FileObject
->FsContext
;
446 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
447 Irp
->IoStatus
.Information
= 0;
448 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
449 return STATUS_SUCCESS
;
452 DPRINT("Fcb %x\n", Fcb
);
455 DPRINT("Closing pipe %wZ\n", &Pipe
->PipeName
);
457 KeLockMutex(&Pipe
->FcbListLock
);
459 Server
= (Fcb
->PipeEnd
== FILE_PIPE_SERVER_END
);
463 /* FIXME: Clean up existing connections here ?? */
465 Pipe
->CurrentInstances
--;
471 if (Fcb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
475 Fcb
->OtherSide
->PipeState
= FILE_PIPE_CLOSING_STATE
;
477 * Signaling the write event. If is possible that an other
478 * thread waits of an empty buffer.
480 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
485 FileObject
->FsContext
= NULL
;
487 RemoveEntryList(&Fcb
->FcbListEntry
);
489 ExFreePool(Fcb
->Data
);
492 KeUnlockMutex(&Pipe
->FcbListLock
);
494 if (Server
&& Pipe
->CurrentInstances
== 0)
496 RtlFreeUnicodeString(&Pipe
->PipeName
);
497 KeLockMutex(&DeviceExt
->PipeListLock
);
498 RemoveEntryList(&Pipe
->PipeListEntry
);
499 KeUnlockMutex(&DeviceExt
->PipeListLock
);
503 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
504 Irp
->IoStatus
.Information
= 0;
505 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
507 return STATUS_SUCCESS
;