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