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