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>
10 /* INCLUDES ******************************************************************/
17 /* FUNCTIONS *****************************************************************/
19 static DRIVER_CANCEL NpfsListeningCancelRoutine
;
21 NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject
,
24 PNPFS_WAITER_ENTRY Waiter
;
26 Waiter
= (PNPFS_WAITER_ENTRY
)&Irp
->Tail
.Overlay
.DriverContext
;
28 DPRINT("NpfsListeningCancelRoutine() called for <%wZ>\n",
29 &Waiter
->Ccb
->Fcb
->PipeName
);
31 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
34 KeLockMutex(&Waiter
->Ccb
->Fcb
->CcbListLock
);
35 RemoveEntryList(&Waiter
->Entry
);
36 KeUnlockMutex(&Waiter
->Ccb
->Fcb
->CcbListLock
);
38 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
39 Irp
->IoStatus
.Information
= 0;
40 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
45 NpfsAddListeningServerInstance(PIRP Irp
,
48 PNPFS_WAITER_ENTRY Entry
;
51 Entry
= (PNPFS_WAITER_ENTRY
)&Irp
->Tail
.Overlay
.DriverContext
;
55 KeLockMutex(&Ccb
->Fcb
->CcbListLock
);
57 IoMarkIrpPending(Irp
);
58 InsertTailList(&Ccb
->Fcb
->WaiterListHead
, &Entry
->Entry
);
60 IoAcquireCancelSpinLock(&oldIrql
);
63 (void)IoSetCancelRoutine(Irp
, NpfsListeningCancelRoutine
);
64 IoReleaseCancelSpinLock(oldIrql
);
65 KeUnlockMutex(&Ccb
->Fcb
->CcbListLock
);
66 return STATUS_PENDING
;
68 IoReleaseCancelSpinLock(oldIrql
);
70 RemoveEntryList(&Entry
->Entry
);
72 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
73 Irp
->IoStatus
.Information
= 0;
74 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
75 KeUnlockMutex(&Ccb
->Fcb
->CcbListLock
);
77 return STATUS_CANCELLED
;
82 NpfsConnectPipe(PIRP Irp
,
85 PIO_STACK_LOCATION IoStack
;
86 PFILE_OBJECT FileObject
;
88 PLIST_ENTRY current_entry
;
93 DPRINT("NpfsConnectPipe()\n");
95 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
97 KeResetEvent(&Ccb
->ConnectEvent
);
98 return STATUS_PIPE_CONNECTED
;
101 if (Ccb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
102 return STATUS_PIPE_CLOSING
;
104 DPRINT("Waiting for connection...\n");
107 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
108 FileObject
= IoStack
->FileObject
;
109 Flags
= FileObject
->Flags
;
111 /* search for a listening client fcb */
112 KeLockMutex(&Fcb
->CcbListLock
);
114 current_entry
= Fcb
->ClientCcbListHead
.Flink
;
115 while (current_entry
!= &Fcb
->ClientCcbListHead
)
117 ClientCcb
= CONTAINING_RECORD(current_entry
,
121 if (ClientCcb
->PipeState
== 0)
123 /* found a passive (waiting) client CCB */
124 DPRINT("Passive (waiting) client CCB found -- wake the client\n");
125 KeSetEvent(&ClientCcb
->ConnectEvent
, IO_NO_INCREMENT
, FALSE
);
130 if (ClientCcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
132 /* found a listening client CCB */
133 DPRINT("Listening client CCB found -- connecting\n");
135 /* connect client and server CCBs */
136 Ccb
->OtherSide
= ClientCcb
;
137 ClientCcb
->OtherSide
= Ccb
;
139 /* set connected state */
140 Ccb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
141 ClientCcb
->PipeState
= FILE_PIPE_CONNECTED_STATE
;
143 KeUnlockMutex(&Fcb
->CcbListLock
);
145 /* FIXME: create and initialize data queues */
147 /* signal client's connect event */
148 DPRINT("Setting the ConnectEvent for %x\n", ClientCcb
);
149 KeSetEvent(&ClientCcb
->ConnectEvent
, IO_NO_INCREMENT
, FALSE
);
151 return STATUS_PIPE_CONNECTED
;
155 current_entry
= current_entry
->Flink
;
158 /* no listening client fcb found */
159 DPRINT("No listening client fcb found -- waiting for client\n");
161 Ccb
->PipeState
= FILE_PIPE_LISTENING_STATE
;
163 Status
= NpfsAddListeningServerInstance(Irp
, Ccb
);
165 KeUnlockMutex(&Fcb
->CcbListLock
);
167 if (Flags
& FO_SYNCHRONOUS_IO
)
169 KeWaitForSingleObject(&Ccb
->ConnectEvent
,
176 DPRINT("NpfsConnectPipe() done (Status %lx)\n", Status
);
183 NpfsDisconnectPipe(PNPFS_CCB Ccb
)
190 DPRINT("NpfsDisconnectPipe()\n");
193 KeLockMutex(&Fcb
->CcbListLock
);
195 if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
197 DPRINT("Pipe is already disconnected\n");
198 Status
= STATUS_SUCCESS
;
200 else if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
202 Server
= (Ccb
->PipeEnd
== FILE_PIPE_SERVER_END
);
203 OtherSide
= Ccb
->OtherSide
;
204 Ccb
->OtherSide
= NULL
;
205 Ccb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
206 /* Lock the server first */
209 ExAcquireFastMutex(&Ccb
->DataListLock
);
210 ExAcquireFastMutex(&OtherSide
->DataListLock
);
214 ExAcquireFastMutex(&OtherSide
->DataListLock
);
215 ExAcquireFastMutex(&Ccb
->DataListLock
);
217 OtherSide
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
218 OtherSide
->OtherSide
= NULL
;
220 * Signaling the write event. If is possible that an other
221 * thread waits for an empty buffer.
223 KeSetEvent(&OtherSide
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
224 KeSetEvent(&OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
227 ExReleaseFastMutex(&OtherSide
->DataListLock
);
228 ExReleaseFastMutex(&Ccb
->DataListLock
);
232 ExReleaseFastMutex(&Ccb
->DataListLock
);
233 ExReleaseFastMutex(&OtherSide
->DataListLock
);
235 Status
= STATUS_SUCCESS
;
237 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
240 PNPFS_WAITER_ENTRY WaitEntry
= NULL
;
241 BOOLEAN Complete
= FALSE
;
244 Entry
= Ccb
->Fcb
->WaiterListHead
.Flink
;
245 while (Entry
!= &Ccb
->Fcb
->WaiterListHead
)
247 WaitEntry
= CONTAINING_RECORD(Entry
, NPFS_WAITER_ENTRY
, Entry
);
248 if (WaitEntry
->Ccb
== Ccb
)
250 RemoveEntryList(Entry
);
251 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DriverContext
);
252 Complete
= (NULL
== IoSetCancelRoutine(Irp
, NULL
));
255 Entry
= Entry
->Flink
;
262 Irp
->IoStatus
.Status
= STATUS_PIPE_BROKEN
;
263 Irp
->IoStatus
.Information
= 0;
264 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
267 Ccb
->PipeState
= FILE_PIPE_DISCONNECTED_STATE
;
268 Status
= STATUS_SUCCESS
;
270 else if (Ccb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
272 Status
= STATUS_PIPE_CLOSING
;
276 Status
= STATUS_UNSUCCESSFUL
;
278 KeUnlockMutex(&Fcb
->CcbListLock
);
284 NpfsWaitPipe(PIRP Irp
,
287 PLIST_ENTRY current_entry
;
290 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
292 LARGE_INTEGER TimeOut
;
294 DPRINT("NpfsWaitPipe\n");
296 WaitPipe
= (PFILE_PIPE_WAIT_FOR_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
299 if (Ccb
->PipeState
!= 0)
301 DPRINT("Pipe is not in passive (waiting) state!\n");
302 return STATUS_UNSUCCESSFUL
;
305 /* search for listening server */
306 current_entry
= Fcb
->ServerCcbListHead
.Flink
;
307 while (current_entry
!= &Fcb
->ServerCcbListHead
)
309 ServerCcb
= CONTAINING_RECORD(current_entry
,
313 if (ServerCcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
315 /* found a listening server CCB */
316 DPRINT("Listening server CCB found -- connecting\n");
318 return STATUS_SUCCESS
;
321 current_entry
= current_entry
->Flink
;
324 /* No listening server fcb found */
326 /* If no timeout specified, use the default one */
327 if (WaitPipe
->TimeoutSpecified
)
328 TimeOut
= WaitPipe
->Timeout
;
330 TimeOut
= Fcb
->TimeOut
;
333 Status
= KeWaitForSingleObject(&Ccb
->ConnectEvent
,
339 DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status
);
346 * FUNCTION: Return current state of a pipe
348 * Irp = Pointer to I/O request packet
349 * IrpSp = Pointer to current stack location of Irp
351 * Status of operation
355 * FUNCTION: Peek at a pipe (get information about messages)
357 * Irp = Pointer to I/O request packet
358 * IoStack = Pointer to current stack location of Irp
360 * Status of operation
363 NpfsPeekPipe(PIRP Irp
,
364 PIO_STACK_LOCATION IoStack
)
366 ULONG OutputBufferLength
;
367 PFILE_PIPE_PEEK_BUFFER Reply
;
372 DPRINT1("NpfsPeekPipe\n");
374 OutputBufferLength
= IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
375 DPRINT1("OutputBufferLength: %lu\n", OutputBufferLength
);
377 /* Validate parameters */
378 if (OutputBufferLength
< sizeof(FILE_PIPE_PEEK_BUFFER
))
380 DPRINT1("Buffer too small\n");
381 return STATUS_INVALID_PARAMETER
;
384 Ccb
= IoStack
->FileObject
->FsContext2
;
385 Reply
= (PFILE_PIPE_PEEK_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
389 Reply
->NamedPipeState
= Ccb
->PipeState
;
391 Reply
->ReadDataAvailable
= Ccb
->ReadDataAvailable
;
392 DPRINT("ReadDataAvailable: %lu\n", Ccb
->ReadDataAvailable
);
394 Reply
->NumberOfMessages
= 0; /* FIXME */
395 Reply
->MessageLength
= 0; /* FIXME */
396 Reply
->Data
[0] = 0; /* FIXME */
398 // Irp->IoStatus.Information = sizeof(FILE_PIPE_PEEK_BUFFER);
400 // Status = STATUS_SUCCESS;
401 Status
= STATUS_NOT_IMPLEMENTED
;
403 DPRINT1("NpfsPeekPipe done\n");
410 NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject
,
413 PIO_STACK_LOCATION IoStack
;
414 PFILE_OBJECT FileObject
;
416 PNPFS_DEVICE_EXTENSION DeviceExt
;
420 DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
422 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
423 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
424 DPRINT("IoStack: %p\n", IoStack
);
425 FileObject
= IoStack
->FileObject
;
426 DPRINT("FileObject: %p\n", FileObject
);
427 Ccb
= FileObject
->FsContext2
;
428 DPRINT("CCB: %p\n", Ccb
);
430 DPRINT("Pipe: %p\n", Fcb
);
431 DPRINT("PipeName: %wZ\n", &Fcb
->PipeName
);
433 Irp
->IoStatus
.Information
= 0;
435 switch (IoStack
->Parameters
.FileSystemControl
.FsControlCode
)
437 case FSCTL_PIPE_ASSIGN_EVENT
:
438 DPRINT1("Assign event not implemented\n");
439 Status
= STATUS_NOT_IMPLEMENTED
;
442 case FSCTL_PIPE_DISCONNECT
:
443 DPRINT("Disconnecting pipe %wZ\n", &Fcb
->PipeName
);
444 Status
= NpfsDisconnectPipe(Ccb
);
447 case FSCTL_PIPE_LISTEN
:
448 DPRINT("Connecting pipe %wZ\n", &Fcb
->PipeName
);
449 Status
= NpfsConnectPipe(Irp
, Ccb
);
452 case FSCTL_PIPE_PEEK
:
453 DPRINT("Peeking pipe %wZ\n", &Fcb
->PipeName
);
454 Status
= NpfsPeekPipe(Irp
, (PIO_STACK_LOCATION
)IoStack
);
457 case FSCTL_PIPE_QUERY_EVENT
:
458 DPRINT1("Query event not implemented\n");
459 Status
= STATUS_NOT_IMPLEMENTED
;
462 case FSCTL_PIPE_TRANSCEIVE
:
463 /* If you implement this, please remove the workaround in
464 lib/kernel32/file/npipe.c function TransactNamedPipe() */
465 DPRINT1("Transceive not implemented\n");
466 Status
= STATUS_NOT_IMPLEMENTED
;
469 case FSCTL_PIPE_WAIT
:
470 DPRINT("Waiting for pipe %wZ\n", &Fcb
->PipeName
);
471 Status
= NpfsWaitPipe(Irp
, Ccb
);
474 case FSCTL_PIPE_IMPERSONATE
:
475 DPRINT1("Impersonate not implemented\n");
476 Status
= STATUS_NOT_IMPLEMENTED
;
479 case FSCTL_PIPE_SET_CLIENT_PROCESS
:
480 DPRINT1("Set client process not implemented\n");
481 Status
= STATUS_NOT_IMPLEMENTED
;
484 case FSCTL_PIPE_QUERY_CLIENT_PROCESS
:
485 DPRINT1("Query client process not implemented\n");
486 Status
= STATUS_NOT_IMPLEMENTED
;
489 case FSCTL_PIPE_INTERNAL_READ
:
490 DPRINT1("Internal read not implemented\n");
491 Status
= STATUS_NOT_IMPLEMENTED
;
494 case FSCTL_PIPE_INTERNAL_WRITE
:
495 DPRINT1("Internal write not implemented\n");
496 Status
= STATUS_NOT_IMPLEMENTED
;
499 case FSCTL_PIPE_INTERNAL_TRANSCEIVE
:
500 DPRINT1("Internal transceive not implemented\n");
501 Status
= STATUS_NOT_IMPLEMENTED
;
504 case FSCTL_PIPE_INTERNAL_READ_OVFLOW
:
505 DPRINT1("Internal read overflow not implemented\n");
506 Status
= STATUS_NOT_IMPLEMENTED
;
510 DPRINT1("Unrecognized IoControlCode: %x\n",
511 IoStack
->Parameters
.FileSystemControl
.FsControlCode
);
512 Status
= STATUS_UNSUCCESSFUL
;
515 if (Status
!= STATUS_PENDING
)
517 Irp
->IoStatus
.Status
= Status
;
519 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
527 NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject
,
530 /* FIXME: Implement */
532 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
533 Irp
->IoStatus
.Information
= 0;
535 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
537 return STATUS_SUCCESS
;