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