2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/fsctrl.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
11 /* INCLUDES ******************************************************************/
18 /* FUNCTIONS *****************************************************************/
20 static DRIVER_CANCEL NpfsListeningCancelRoutine
;
22 NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject
,
25 PNPFS_WAITER_ENTRY Waiter
;
27 Waiter
= (PNPFS_WAITER_ENTRY
)&Irp
->Tail
.Overlay
.DriverContext
;
29 DPRINT("NpfsListeningCancelRoutine() called for <%wZ>\n",
30 &Waiter
->Ccb
->Fcb
->PipeName
);
32 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
35 KeLockMutex(&Waiter
->Ccb
->Fcb
->CcbListLock
);
36 RemoveEntryList(&Waiter
->Entry
);
37 KeUnlockMutex(&Waiter
->Ccb
->Fcb
->CcbListLock
);
39 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
40 Irp
->IoStatus
.Information
= 0;
41 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
46 NpfsAddListeningServerInstance(PIRP Irp
,
49 PNPFS_WAITER_ENTRY Entry
;
52 Entry
= (PNPFS_WAITER_ENTRY
)&Irp
->Tail
.Overlay
.DriverContext
;
56 KeLockMutex(&Ccb
->Fcb
->CcbListLock
);
58 IoMarkIrpPending(Irp
);
59 InsertTailList(&Ccb
->Fcb
->WaiterListHead
, &Entry
->Entry
);
61 IoAcquireCancelSpinLock(&oldIrql
);
64 (void)IoSetCancelRoutine(Irp
, NpfsListeningCancelRoutine
);
65 IoReleaseCancelSpinLock(oldIrql
);
66 KeUnlockMutex(&Ccb
->Fcb
->CcbListLock
);
67 return STATUS_PENDING
;
69 IoReleaseCancelSpinLock(oldIrql
);
71 RemoveEntryList(&Entry
->Entry
);
73 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
74 Irp
->IoStatus
.Information
= 0;
75 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
76 KeUnlockMutex(&Ccb
->Fcb
->CcbListLock
);
78 return STATUS_CANCELLED
;
83 NpfsConnectPipe(PIRP Irp
,
86 PIO_STACK_LOCATION IoStack
;
87 PFILE_OBJECT FileObject
;
89 PLIST_ENTRY current_entry
;
94 DPRINT("NpfsConnectPipe()\n");
96 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
98 KeResetEvent(&Ccb
->ConnectEvent
);
99 return STATUS_PIPE_CONNECTED
;
102 if (Ccb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
103 return STATUS_PIPE_CLOSING
;
105 DPRINT("Waiting for connection...\n");
108 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
109 FileObject
= IoStack
->FileObject
;
110 Flags
= FileObject
->Flags
;
112 /* search for a listening client fcb */
113 KeLockMutex(&Fcb
->CcbListLock
);
115 current_entry
= Fcb
->ClientCcbListHead
.Flink
;
116 while (current_entry
!= &Fcb
->ClientCcbListHead
)
118 ClientCcb
= CONTAINING_RECORD(current_entry
,
122 if (ClientCcb
->PipeState
== 0)
124 /* found a passive (waiting) client CCB */
125 DPRINT("Passive (waiting) client CCB found -- wake the client\n");
126 KeSetEvent(&ClientCcb
->ConnectEvent
, IO_NO_INCREMENT
, FALSE
);
131 if (ClientCcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
133 /* found a listening client CCB */
134 DPRINT("Listening client CCB found -- connecting\n");
136 /* connect client and server CCBs */
137 Ccb
->OtherSide
= ClientCcb
;
138 ClientCcb
->OtherSide
= Ccb
;
140 /* set connected state */
141 Ccb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
142 ClientCcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
144 KeUnlockMutex(&Fcb
->CcbListLock
);
146 /* FIXME: create and initialize data queues */
148 /* signal client's connect event */
149 DPRINT("Setting the ConnectEvent for %x\n", ClientCcb
);
150 KeSetEvent(&ClientCcb
->ConnectEvent
, IO_NO_INCREMENT
, FALSE
);
152 return STATUS_PIPE_CONNECTED
;
156 current_entry
= current_entry
->Flink
;
159 /* no listening client fcb found */
160 DPRINT("No listening client fcb found -- waiting for client\n");
162 Ccb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
164 Status
= NpfsAddListeningServerInstance(Irp
, Ccb
);
166 KeUnlockMutex(&Fcb
->CcbListLock
);
168 if (Flags
& FO_SYNCHRONOUS_IO
)
170 KeWaitForSingleObject(&Ccb
->ConnectEvent
,
177 DPRINT("NpfsConnectPipe() done (Status %lx)\n", Status
);
184 NpfsDisconnectPipe(PNPFS_CCB Ccb
)
191 DPRINT("NpfsDisconnectPipe()\n");
194 KeLockMutex(&Fcb
->CcbListLock
);
196 if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
198 DPRINT("Pipe is already disconnected\n");
199 Status
= STATUS_PIPE_DISCONNECTED
;
201 else if ((!Ccb
->OtherSide
) && (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
))
203 ExAcquireFastMutex(&Ccb
->DataListLock
);
204 Ccb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
205 ExReleaseFastMutex(&Ccb
->DataListLock
);
206 Status
= STATUS_SUCCESS
;
208 else if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
210 Server
= (Ccb
->PipeEnd
== FILE_PIPE_SERVER_END
);
211 OtherSide
= Ccb
->OtherSide
;
212 //Ccb->OtherSide = NULL;
213 Ccb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
214 /* Lock the server first */
217 ExAcquireFastMutex(&Ccb
->DataListLock
);
218 ExAcquireFastMutex(&OtherSide
->DataListLock
);
222 ExAcquireFastMutex(&OtherSide
->DataListLock
);
223 ExAcquireFastMutex(&Ccb
->DataListLock
);
225 OtherSide
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
226 //OtherSide->OtherSide = NULL;
228 * Signaling the write event. If is possible that an other
229 * thread waits for an empty buffer.
231 KeSetEvent(&OtherSide
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
232 KeSetEvent(&OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
235 ExReleaseFastMutex(&OtherSide
->DataListLock
);
236 ExReleaseFastMutex(&Ccb
->DataListLock
);
240 ExReleaseFastMutex(&Ccb
->DataListLock
);
241 ExReleaseFastMutex(&OtherSide
->DataListLock
);
243 Status
= STATUS_SUCCESS
;
245 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
248 PNPFS_WAITER_ENTRY WaitEntry
= NULL
;
249 BOOLEAN Complete
= FALSE
;
252 Entry
= Ccb
->Fcb
->WaiterListHead
.Flink
;
253 while (Entry
!= &Ccb
->Fcb
->WaiterListHead
)
255 WaitEntry
= CONTAINING_RECORD(Entry
, NPFS_WAITER_ENTRY
, Entry
);
256 if (WaitEntry
->Ccb
== Ccb
)
258 RemoveEntryList(Entry
);
259 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DriverContext
);
260 Complete
= (NULL
== IoSetCancelRoutine(Irp
, NULL
));
263 Entry
= Entry
->Flink
;
270 Irp
->IoStatus
.Status
= STATUS_PIPE_BROKEN
;
271 Irp
->IoStatus
.Information
= 0;
272 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
275 Ccb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
276 Status
= STATUS_SUCCESS
;
278 else if (Ccb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
280 Status
= STATUS_PIPE_CLOSING
;
284 Status
= STATUS_UNSUCCESSFUL
;
286 KeUnlockMutex(&Fcb
->CcbListLock
);
292 NpfsWaitPipe(PIRP Irp
,
295 PLIST_ENTRY current_entry
;
299 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
300 LARGE_INTEGER TimeOut
;
301 UNICODE_STRING PipeName
;
304 DPRINT("NpfsWaitPipe\n");
306 WaitPipe
= (PFILE_PIPE_WAIT_FOR_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
308 /* Fail, if the CCB does not represent the root directory */
309 if (Ccb
->Type
!= CCB_DIRECTORY
)
310 return STATUS_ILLEGAL_FUNCTION
;
312 /* Calculate the pipe name length and allocate the buffer */
313 PipeName
.Length
= WaitPipe
->NameLength
+ sizeof(WCHAR
);
314 PipeName
.MaximumLength
= PipeName
.Length
+ sizeof(WCHAR
);
315 PipeName
.Buffer
= ExAllocatePool(NonPagedPool
, PipeName
.MaximumLength
);
316 if (PipeName
.Buffer
== NULL
)
318 DPRINT1("Could not allocate memory for the pipe name!\n");
319 return STATUS_NO_MEMORY
;
322 /* Copy the pipe name into the buffer, prepend a backslash and append a 0 character */
323 PipeName
.Buffer
[0] = L
'\\';
324 RtlCopyMemory(&PipeName
.Buffer
[1],
326 WaitPipe
->NameLength
);
327 PipeName
.Buffer
[PipeName
.Length
/ sizeof(WCHAR
)] = 0;
329 DPRINT("Waiting for Pipe %wZ\n", &PipeName
);
334 /* Lock the pipe list */
335 KeLockMutex(&Vcb
->PipeListLock
);
337 /* File a pipe with the given name */
338 Fcb
= NpfsFindPipe(Vcb
,
341 /* Unlock the pipe list */
342 KeUnlockMutex(&Vcb
->PipeListLock
);
344 /* Release the pipe name buffer */
345 ExFreePool(PipeName
.Buffer
);
347 /* Fail if not pipe was found */
350 DPRINT("No pipe found!\n", Fcb
);
351 return STATUS_OBJECT_NAME_NOT_FOUND
;
354 DPRINT("Fcb %p\n", Fcb
);
356 /* search for listening server */
357 current_entry
= Fcb
->ServerCcbListHead
.Flink
;
358 while (current_entry
!= &Fcb
->ServerCcbListHead
)
360 ServerCcb
= CONTAINING_RECORD(current_entry
,
364 if (ServerCcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
366 /* found a listening server CCB */
367 DPRINT("Listening server CCB found -- connecting\n");
369 return STATUS_SUCCESS
;
372 current_entry
= current_entry
->Flink
;
375 /* No listening server fcb found */
377 /* If no timeout specified, use the default one */
378 if (WaitPipe
->TimeoutSpecified
)
379 TimeOut
= WaitPipe
->Timeout
;
381 TimeOut
= Fcb
->TimeOut
;
384 Status
= KeWaitForSingleObject(&Ccb
->ConnectEvent
,
390 DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status
);
397 * FUNCTION: Return current state of a pipe
399 * Irp = Pointer to I/O request packet
400 * IrpSp = Pointer to current stack location of Irp
402 * Status of operation
406 * FUNCTION: Peek at a pipe (get information about messages)
408 * Irp = Pointer to I/O request packet
409 * IoStack = Pointer to current stack location of Irp
411 * Status of operation
414 NpfsPeekPipe(PIRP Irp
,
415 PIO_STACK_LOCATION IoStack
)
417 ULONG OutputBufferLength
;
418 ULONG ReturnLength
= 0;
419 PFILE_PIPE_PEEK_BUFFER Reply
;
423 ULONG MessageCount
= 0;
425 ULONG ReadDataAvailable
;
428 DPRINT("NpfsPeekPipe\n");
430 OutputBufferLength
= IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
431 DPRINT("OutputBufferLength: %lu\n", OutputBufferLength
);
433 /* Validate parameters */
434 if (OutputBufferLength
< sizeof(FILE_PIPE_PEEK_BUFFER
))
436 DPRINT1("Buffer too small\n");
437 return STATUS_INVALID_PARAMETER
;
440 Ccb
= IoStack
->FileObject
->FsContext2
;
441 Reply
= (PFILE_PIPE_PEEK_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
445 Reply
->NamedPipeState
= Ccb
->PipeState
;
447 Reply
->ReadDataAvailable
= Ccb
->ReadDataAvailable
;
448 DPRINT("ReadDataAvailable: %lu\n", Ccb
->ReadDataAvailable
);
450 ExAcquireFastMutex(&Ccb
->DataListLock
);
451 BufferPtr
= Ccb
->ReadPtr
;
452 DPRINT("BufferPtr = %x\n", BufferPtr
);
453 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
455 DPRINT("Byte Stream Mode\n");
456 Reply
->MessageLength
= Ccb
->ReadDataAvailable
;
457 DPRINT("Reply->MessageLength %lu\n",Reply
->MessageLength
);
460 if (Reply
->Data
[0] && (OutputBufferLength
>= Ccb
->ReadDataAvailable
+ FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0])))
462 ReturnLength
= Ccb
->ReadDataAvailable
;
463 memcpy(&Reply
->Data
[0], (PVOID
)BufferPtr
, Ccb
->ReadDataAvailable
);
468 DPRINT("Message Mode\n");
469 ReadDataAvailable
=Ccb
->ReadDataAvailable
;
471 if (ReadDataAvailable
> 0)
473 memcpy(&Reply
->MessageLength
, BufferPtr
, sizeof(ULONG
));
475 while ((ReadDataAvailable
> 0) && (BufferPtr
< Ccb
->WritePtr
))
477 memcpy(&MessageLength
, BufferPtr
, sizeof(MessageLength
));
479 ASSERT(MessageLength
> 0);
481 DPRINT("MessageLength = %lu\n",MessageLength
);
482 ReadDataAvailable
-= MessageLength
;
485 /* If its the first message, copy the Message if the size of buffer is large enough */
489 && (OutputBufferLength
>= (MessageLength
+ FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]))))
491 memcpy(&Reply
->Data
[0], (PVOID
)((ULONG_PTR
)BufferPtr
+ sizeof(MessageLength
)), MessageLength
);
492 ReturnLength
= MessageLength
;
496 BufferPtr
=(PVOID
)((ULONG_PTR
)BufferPtr
+ MessageLength
+ sizeof(MessageLength
));
497 DPRINT("BufferPtr = %x\n", BufferPtr
);
498 DPRINT("ReadDataAvailable: %lu\n", ReadDataAvailable
);
501 if (ReadDataAvailable
!= 0)
503 DPRINT1("Possible memory corruption.\n");
508 ExReleaseFastMutex(&Ccb
->DataListLock
);
510 Reply
->NumberOfMessages
= MessageCount
;
512 Irp
->IoStatus
.Information
= ReturnLength
+ FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]);
513 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
515 Status
= STATUS_SUCCESS
;
517 DPRINT("NpfsPeekPipe done\n");
524 NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject
,
527 PIO_STACK_LOCATION IoStack
;
528 PFILE_OBJECT FileObject
;
534 DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
536 Vcb
= (PNPFS_VCB
)DeviceObject
->DeviceExtension
;
537 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
538 DPRINT("IoStack: %p\n", IoStack
);
539 FileObject
= IoStack
->FileObject
;
540 DPRINT("FileObject: %p\n", FileObject
);
541 Ccb
= FileObject
->FsContext2
;
542 DPRINT("CCB: %p\n", Ccb
);
544 DPRINT("Pipe: %p\n", Fcb
);
545 DPRINT("PipeName: %wZ\n", &Fcb
->PipeName
);
547 Irp
->IoStatus
.Information
= 0;
549 switch (IoStack
->Parameters
.FileSystemControl
.FsControlCode
)
551 case FSCTL_PIPE_ASSIGN_EVENT
:
552 DPRINT1("Assign event not implemented\n");
553 Status
= STATUS_NOT_IMPLEMENTED
;
556 case FSCTL_PIPE_DISCONNECT
:
557 DPRINT("Disconnecting pipe %wZ\n", &Fcb
->PipeName
);
558 Status
= NpfsDisconnectPipe(Ccb
);
561 case FSCTL_PIPE_LISTEN
:
562 DPRINT("Connecting pipe %wZ\n", &Fcb
->PipeName
);
563 Status
= NpfsConnectPipe(Irp
, Ccb
);
566 case FSCTL_PIPE_PEEK
:
567 DPRINT("Peeking pipe %wZ\n", &Fcb
->PipeName
);
568 Status
= NpfsPeekPipe(Irp
, (PIO_STACK_LOCATION
)IoStack
);
571 case FSCTL_PIPE_QUERY_EVENT
:
572 DPRINT1("Query event not implemented\n");
573 Status
= STATUS_NOT_IMPLEMENTED
;
576 case FSCTL_PIPE_TRANSCEIVE
:
577 /* If you implement this, please remove the workaround in
578 lib/kernel32/file/npipe.c function TransactNamedPipe() */
579 DPRINT1("Transceive not implemented\n");
580 Status
= STATUS_NOT_IMPLEMENTED
;
583 case FSCTL_PIPE_WAIT
:
584 DPRINT("Waiting for pipe %wZ\n", &Fcb
->PipeName
);
585 Status
= NpfsWaitPipe(Irp
, Ccb
);
588 case FSCTL_PIPE_IMPERSONATE
:
589 DPRINT1("Impersonate not implemented\n");
590 Status
= STATUS_NOT_IMPLEMENTED
;
593 case FSCTL_PIPE_SET_CLIENT_PROCESS
:
594 DPRINT1("Set client process not implemented\n");
595 Status
= STATUS_NOT_IMPLEMENTED
;
598 case FSCTL_PIPE_QUERY_CLIENT_PROCESS
:
599 DPRINT1("Query client process not implemented\n");
600 Status
= STATUS_NOT_IMPLEMENTED
;
603 case FSCTL_PIPE_INTERNAL_READ
:
604 DPRINT1("Internal read not implemented\n");
605 Status
= STATUS_NOT_IMPLEMENTED
;
608 case FSCTL_PIPE_INTERNAL_WRITE
:
609 DPRINT1("Internal write not implemented\n");
610 Status
= STATUS_NOT_IMPLEMENTED
;
613 case FSCTL_PIPE_INTERNAL_TRANSCEIVE
:
614 DPRINT1("Internal transceive not implemented\n");
615 Status
= STATUS_NOT_IMPLEMENTED
;
618 case FSCTL_PIPE_INTERNAL_READ_OVFLOW
:
619 DPRINT1("Internal read overflow not implemented\n");
620 Status
= STATUS_NOT_IMPLEMENTED
;
624 DPRINT1("Unrecognized IoControlCode: %x\n",
625 IoStack
->Parameters
.FileSystemControl
.FsControlCode
);
626 Status
= STATUS_UNSUCCESSFUL
;
629 if (Status
!= STATUS_PENDING
)
631 Irp
->IoStatus
.Status
= Status
;
633 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
641 NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject
,
644 /* FIXME: Implement */
646 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
647 Irp
->IoStatus
.Information
= 0;
649 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
651 return STATUS_SUCCESS
;