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