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