update for HEAD-2003091401
[reactos.git] / drivers / fs / np / fsctrl.c
1 /* $Id$
2  *
3  * COPYRIGHT:  See COPYING in the top level directory
4  * PROJECT:    ReactOS kernel
5  * FILE:       services/fs/np/fsctrl.c
6  * PURPOSE:    Named pipe filesystem
7  * PROGRAMMER: David Welch <welch@cwcom.net>
8  *             Eric Kohl <ekohl@rz-online.de>
9  */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include "npfs.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* FUNCTIONS *****************************************************************/
21
22 static NTSTATUS
23 NpfsConnectPipe(PNPFS_FCB Fcb)
24 {
25    PNPFS_PIPE Pipe;
26    PLIST_ENTRY current_entry;
27    PNPFS_FCB ClientFcb;
28    NTSTATUS Status;
29
30    DPRINT("NpfsConnectPipe()\n");
31
32    if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
33      return STATUS_PIPE_CONNECTED;
34
35    if (Fcb->PipeState == FILE_PIPE_CLOSING_STATE)
36      return STATUS_PIPE_CLOSING;
37
38    /*
39     * Acceptable states are: FILE_PIPE_DISCONNECTED_STATE and
40     *                        FILE_PIPE_LISTENING_STATE
41     */
42
43    DPRINT("Waiting for connection...\n");
44
45    Pipe = Fcb->Pipe;
46
47    Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
48
49    /* search for a listening client fcb */
50
51    current_entry = Pipe->ClientFcbListHead.Flink;
52    while (current_entry != &Pipe->ClientFcbListHead)
53      {
54         ClientFcb = CONTAINING_RECORD(current_entry,
55                                       NPFS_FCB,
56                                       FcbListEntry);
57         
58         if ((ClientFcb->PipeState == FILE_PIPE_LISTENING_STATE)
59             || (ClientFcb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
60           {
61              break;
62           }
63         
64         current_entry = current_entry->Flink;
65      }
66    
67    if ((current_entry != &Pipe->ClientFcbListHead)
68        && (ClientFcb->PipeState == FILE_PIPE_LISTENING_STATE))
69      {
70         /* found a listening client fcb */
71         DPRINT("Listening client fcb found -- connecting\n");
72
73         /* connect client and server fcb's */
74         Fcb->OtherSide = ClientFcb;
75         ClientFcb->OtherSide = Fcb;
76
77         /* set connected state */
78         Fcb->PipeState = FILE_PIPE_CONNECTED_STATE;
79         ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
80
81         /* FIXME: create and initialize data queues */
82
83         /* signal client's connect event */
84         KeSetEvent(&ClientFcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
85
86      }
87    else if ((current_entry != &Pipe->ClientFcbListHead)
88             && (ClientFcb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
89      {
90         /* found a disconnected client fcb */
91         DPRINT("Disconnected client fcb found - notifying client\n");
92
93         /* signal client's connect event */
94         KeSetEvent(&ClientFcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
95      }
96    else
97      {
98         /* no listening client fcb found */
99         DPRINT("No listening client fcb found -- waiting for client\n");
100         Status = KeWaitForSingleObject(&Fcb->ConnectEvent,
101                                        UserRequest,
102                                        KernelMode,
103                                        FALSE,
104                                        NULL);
105
106         DPRINT("Finished waiting! Status: %x\n", Status);
107      }
108
109
110    DPRINT("Client Fcb: %p\n", Fcb->OtherSide);
111
112    return STATUS_PIPE_CONNECTED;
113 }
114
115
116 static NTSTATUS
117 NpfsDisconnectPipe(PNPFS_FCB Fcb)
118 {
119   PNPFS_FCB ServerFcb;
120
121   DPRINT("NpfsDisconnectPipe()\n");
122
123   if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
124     return(STATUS_SUCCESS);
125
126   if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
127     {
128       Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
129       Fcb->OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
130
131       /* FIXME: remove data queue(s) */
132
133       Fcb->OtherSide->OtherSide = NULL;
134       Fcb->OtherSide = NULL;
135
136       DPRINT("Pipe disconnected\n");
137       return(STATUS_SUCCESS);
138     }
139
140   if (Fcb->PipeState == FILE_PIPE_CLOSING_STATE)
141     {
142       Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
143
144       /* FIXME: remove data queue(s) */
145
146       DPRINT("Pipe disconnected\n");
147       return(STATUS_SUCCESS);
148     }
149
150   return(STATUS_UNSUCCESSFUL);
151 }
152
153
154 static NTSTATUS
155 NpfsWaitPipe(PIRP Irp,
156              PNPFS_FCB Fcb)
157 {
158   PNPFS_PIPE Pipe;
159   PLIST_ENTRY current_entry;
160   PNPFS_FCB ServerFcb;
161   PNPFS_WAIT_PIPE WaitPipe;
162   NTSTATUS Status;
163
164   DPRINT("NpfsWaitPipe\n");
165
166   WaitPipe = (PNPFS_WAIT_PIPE)Irp->AssociatedIrp.SystemBuffer;
167   Pipe = Fcb->Pipe;
168
169   /* search for listening server */
170   current_entry = Pipe->ServerFcbListHead.Flink;
171   while (current_entry != &Pipe->ServerFcbListHead)
172     {
173       ServerFcb = CONTAINING_RECORD(current_entry,
174                                     NPFS_FCB,
175                                     FcbListEntry);
176
177       if (ServerFcb->PipeState == FILE_PIPE_LISTENING_STATE)
178         break;
179
180       current_entry = current_entry->Flink;
181     }
182
183   if (current_entry != &Pipe->ServerFcbListHead)
184     {
185       /* found a listening server fcb */
186       DPRINT("Listening server fcb found -- connecting\n");
187
188       Status = STATUS_SUCCESS;
189     }
190   else
191     {
192       /* no listening server fcb found -- wait for one */
193       Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
194
195       Status = KeWaitForSingleObject(&Fcb->ConnectEvent,
196                                      UserRequest,
197                                      KernelMode,
198                                      FALSE,
199                                      &WaitPipe->Timeout);
200     }
201
202   return(Status);
203 }
204
205
206 static NTSTATUS
207 NpfsGetState(
208   PIRP Irp,
209   PIO_STACK_LOCATION IrpSp)
210 /*
211  * FUNCTION: Return current state of a pipe
212  * ARGUMENTS:
213  *     Irp   = Pointer to I/O request packet
214  *     IrpSp = Pointer to current stack location of Irp
215  * RETURNS:
216  *     Status of operation
217  */
218 {
219   ULONG OutputBufferLength;
220   PNPFS_GET_STATE Reply;
221   NTSTATUS Status;
222   PNPFS_PIPE Pipe;
223   PNPFS_FCB Fcb;
224
225   OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
226
227   /* Validate parameters */
228   if (OutputBufferLength >= sizeof(NPFS_GET_STATE))
229   {
230     Fcb = IrpSp->FileObject->FsContext;
231     Reply = (PNPFS_GET_STATE)Irp->AssociatedIrp.SystemBuffer;
232     Pipe = Fcb->Pipe;
233
234     if (Pipe->PipeWriteMode == FILE_PIPE_MESSAGE_MODE)
235     {
236       Reply->WriteModeMessage = TRUE;
237     }
238     else
239     {
240       Reply->WriteModeMessage = FALSE;
241     }
242
243     if (Pipe->PipeReadMode == FILE_PIPE_MESSAGE_MODE)
244     {
245       Reply->ReadModeMessage = TRUE;
246     }
247     else
248     {
249       Reply->ReadModeMessage = FALSE;
250     }
251
252     if (Pipe->PipeBlockMode == FILE_PIPE_QUEUE_OPERATION)
253     {
254       Reply->NonBlocking = TRUE;
255     }
256     else
257     {
258       Reply->NonBlocking = FALSE;
259     }
260
261     Reply->InBufferSize = Pipe->InboundQuota;
262
263     Reply->OutBufferSize = Pipe->OutboundQuota;
264
265     Reply->Timeout = Pipe->TimeOut;
266
267     Status = STATUS_SUCCESS;
268   }
269   else
270   {
271     Status = STATUS_INVALID_PARAMETER;
272   }
273
274   DPRINT("Status (0x%X).\n", Status);
275
276   return Status;
277 }
278
279
280 static NTSTATUS
281 NpfsSetState(
282   PIRP Irp,
283   PIO_STACK_LOCATION IrpSp)
284 /*
285  * FUNCTION: Set state of a pipe
286  * ARGUMENTS:
287  *     Irp   = Pointer to I/O request packet
288  *     IrpSp = Pointer to current stack location of Irp
289  * RETURNS:
290  *     Status of operation
291  */
292 {
293   ULONG InputBufferLength;
294   PNPFS_SET_STATE Request;
295   PNPFS_PIPE Pipe;
296   NTSTATUS Status;
297   PNPFS_FCB Fcb;
298
299   InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
300
301   /* Validate parameters */
302   if (InputBufferLength >= sizeof(NPFS_SET_STATE))
303   {
304     Fcb = IrpSp->FileObject->FsContext;
305     Request = (PNPFS_SET_STATE)Irp->AssociatedIrp.SystemBuffer;
306     Pipe = Fcb->Pipe;
307
308     if (Request->WriteModeMessage)
309     {
310       Pipe->PipeWriteMode = FILE_PIPE_MESSAGE_MODE;
311     }
312     else
313     {
314       Pipe->PipeWriteMode = FILE_PIPE_BYTE_STREAM_MODE;
315     }
316
317     if (Request->ReadModeMessage)
318     {
319       Pipe->PipeReadMode = FILE_PIPE_MESSAGE_MODE;
320     }
321     else
322     {
323       Pipe->PipeReadMode = FILE_PIPE_BYTE_STREAM_MODE;
324     }
325
326     if (Request->NonBlocking)
327     {
328       Pipe->PipeBlockMode = FILE_PIPE_QUEUE_OPERATION;
329     }
330     else
331     {
332       Pipe->PipeBlockMode = FILE_PIPE_COMPLETE_OPERATION;
333     }
334
335     Pipe->InboundQuota = Request->InBufferSize;
336
337     Pipe->OutboundQuota = Request->OutBufferSize;
338
339     Pipe->TimeOut = Request->Timeout;
340
341     Status = STATUS_SUCCESS;
342   }
343   else
344   {
345     Status = STATUS_INVALID_PARAMETER;
346   }
347
348   DPRINT("Status (0x%X).\n", Status);
349
350   return Status;
351 }
352
353
354 static NTSTATUS
355 NpfsPeekPipe(PIRP Irp,
356              PIO_STACK_LOCATION IoStack)
357 /*
358  * FUNCTION: Peek at a pipe (get information about messages)
359  * ARGUMENTS:
360  *     Irp = Pointer to I/O request packet
361  *     IoStack = Pointer to current stack location of Irp
362  * RETURNS:
363  *     Status of operation
364  */
365 {
366   ULONG OutputBufferLength;
367   PNPFS_PIPE Pipe;
368   PFILE_PIPE_PEEK_BUFFER Reply;
369   PNPFS_FCB Fcb;
370   NTSTATUS Status;
371
372   DPRINT("NpfsPeekPipe\n");
373
374   OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
375
376   /* Validate parameters */
377   if (OutputBufferLength < sizeof(FILE_PIPE_PEEK_BUFFER))
378     {
379       DPRINT("Buffer too small\n");
380       return(STATUS_INVALID_PARAMETER);
381     }
382
383   Fcb = IoStack->FileObject->FsContext;
384   Reply = (PFILE_PIPE_PEEK_BUFFER)Irp->AssociatedIrp.SystemBuffer;
385   Pipe = Fcb->Pipe;
386
387   Status = STATUS_NOT_IMPLEMENTED;
388
389   return(Status);
390 }
391
392
393
394 NTSTATUS STDCALL
395 NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
396                       PIRP Irp)
397 {
398   PEXTENDED_IO_STACK_LOCATION IoStack;
399   PFILE_OBJECT FileObject;
400   NTSTATUS Status;
401   PNPFS_DEVICE_EXTENSION DeviceExt;
402   PNPFS_PIPE Pipe;
403   PNPFS_FCB Fcb;
404
405   DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
406
407   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
408   IoStack = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation(Irp);
409   DPRINT("IoStack: %p\n", IoStack);
410   FileObject = IoStack->FileObject;
411   DPRINT("FileObject: %p\n", FileObject);
412   Fcb = FileObject->FsContext;
413   DPRINT("Fcb: %p\n", Fcb);
414   Pipe = Fcb->Pipe;
415   DPRINT("Pipe: %p\n", Pipe);
416   DPRINT("PipeName: %wZ\n", &Pipe->PipeName);
417
418   switch (IoStack->Parameters.FileSystemControl.FsControlCode)
419     {
420       case FSCTL_PIPE_ASSIGN_EVENT:
421         DPRINT("Assign event\n");
422         Status = STATUS_NOT_IMPLEMENTED;
423         break;
424
425       case FSCTL_PIPE_DISCONNECT:
426         DPRINT("Disconnecting pipe %wZ\n", &Pipe->PipeName);
427         Status = NpfsDisconnectPipe(Fcb);
428         break;
429
430       case FSCTL_PIPE_LISTEN:
431         DPRINT("Connecting pipe %wZ\n", &Pipe->PipeName);
432         Status = NpfsConnectPipe(Fcb);
433         break;
434
435       case FSCTL_PIPE_PEEK:
436         DPRINT("Peeking pipe %wZ\n", &Pipe->PipeName);
437         Status = NpfsPeekPipe(Irp, IoStack);
438         break;
439
440       case FSCTL_PIPE_QUERY_EVENT:
441         DPRINT("Query event\n");
442         Status = STATUS_NOT_IMPLEMENTED;
443         break;
444
445       case FSCTL_PIPE_TRANSCEIVE:
446         DPRINT("Transceive\n");
447         Status = STATUS_NOT_IMPLEMENTED;
448         break;
449
450       case FSCTL_PIPE_WAIT:
451         DPRINT("Waiting for pipe %wZ\n", &Pipe->PipeName);
452         Status = NpfsWaitPipe(Irp, Fcb);
453         break;
454
455       case FSCTL_PIPE_IMPERSONATE:
456         DPRINT("Impersonate\n");
457         Status = STATUS_NOT_IMPLEMENTED;
458         break;
459
460       case FSCTL_PIPE_SET_CLIENT_PROCESS:
461         DPRINT("Set client process\n");
462         Status = STATUS_NOT_IMPLEMENTED;
463         break;
464
465       case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
466         DPRINT("Query client process\n");
467         Status = STATUS_NOT_IMPLEMENTED;
468         break;
469
470       case FSCTL_PIPE_GET_STATE:
471         DPRINT("Get state\n");
472         Status = NpfsGetState(Irp, IoStack);
473         break;
474
475       case FSCTL_PIPE_SET_STATE:
476         DPRINT("Set state\n");
477         Status = NpfsSetState(Irp, IoStack);
478         break;
479
480       case FSCTL_PIPE_INTERNAL_READ:
481         DPRINT("Internal read\n");
482         Status = STATUS_NOT_IMPLEMENTED;
483         break;
484
485       case FSCTL_PIPE_INTERNAL_WRITE:
486         DPRINT("Internal write\n");
487         Status = STATUS_NOT_IMPLEMENTED;
488         break;
489
490       case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
491         DPRINT("Internal transceive\n");
492         Status = STATUS_NOT_IMPLEMENTED;
493         break;
494
495       case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
496         DPRINT("Internal read overflow\n");
497         Status = STATUS_NOT_IMPLEMENTED;
498         break;
499
500       default:
501         DPRINT("IoControlCode: %x\n", IoStack->Parameters.FileSystemControl.IoControlCode)
502         Status = STATUS_UNSUCCESSFUL;
503     }
504
505   Irp->IoStatus.Status = Status;
506   Irp->IoStatus.Information = 0;
507
508   IoCompleteRequest(Irp, IO_NO_INCREMENT);
509
510   return(Status);
511 }
512
513 /* EOF */