[NPFS]
[reactos.git] / reactos / 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 * Michael Martin
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include "npfs.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
19
20 /* FUNCTIONS *****************************************************************/
21
22 static DRIVER_CANCEL NpfsListeningCancelRoutine;
23 static VOID NTAPI
24 NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
25 IN PIRP Irp)
26 {
27 PNPFS_WAITER_ENTRY Waiter;
28
29 Waiter = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
30
31 DPRINT("NpfsListeningCancelRoutine() called for <%wZ>\n",
32 &Waiter->Ccb->Fcb->PipeName);
33
34 IoReleaseCancelSpinLock(Irp->CancelIrql);
35
36
37 KeLockMutex(&Waiter->Ccb->Fcb->CcbListLock);
38 RemoveEntryList(&Waiter->Entry);
39 KeUnlockMutex(&Waiter->Ccb->Fcb->CcbListLock);
40
41 Irp->IoStatus.Status = STATUS_CANCELLED;
42 Irp->IoStatus.Information = 0;
43 IoCompleteRequest(Irp, IO_NO_INCREMENT);
44 }
45
46
47 static NTSTATUS
48 NpfsAddListeningServerInstance(PIRP Irp,
49 PNPFS_CCB Ccb)
50 {
51 PNPFS_WAITER_ENTRY Entry;
52 KIRQL oldIrql;
53
54 Entry = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
55
56 Entry->Ccb = Ccb;
57
58 KeLockMutex(&Ccb->Fcb->CcbListLock);
59
60 IoMarkIrpPending(Irp);
61 InsertTailList(&Ccb->Fcb->WaiterListHead, &Entry->Entry);
62
63 IoAcquireCancelSpinLock(&oldIrql);
64 if (!Irp->Cancel)
65 {
66 (void)IoSetCancelRoutine(Irp, NpfsListeningCancelRoutine);
67 IoReleaseCancelSpinLock(oldIrql);
68 KeUnlockMutex(&Ccb->Fcb->CcbListLock);
69 return STATUS_PENDING;
70 }
71 IoReleaseCancelSpinLock(oldIrql);
72
73 RemoveEntryList(&Entry->Entry);
74
75 Irp->IoStatus.Status = STATUS_CANCELLED;
76 Irp->IoStatus.Information = 0;
77 IoCompleteRequest(Irp, IO_NO_INCREMENT);
78 KeUnlockMutex(&Ccb->Fcb->CcbListLock);
79
80 return STATUS_CANCELLED;
81 }
82
83
84 static NTSTATUS
85 NpfsConnectPipe(PIRP Irp,
86 PNPFS_CCB Ccb)
87 {
88 PIO_STACK_LOCATION IoStack;
89 PFILE_OBJECT FileObject;
90 ULONG Flags;
91 PLIST_ENTRY current_entry;
92 PNPFS_FCB Fcb;
93 PNPFS_CCB ClientCcb;
94 NTSTATUS Status;
95
96 DPRINT("NpfsConnectPipe()\n");
97
98 /* Fail, if the CCB is not a pipe CCB */
99 if (Ccb->Type != CCB_PIPE)
100 {
101 DPRINT1("Not a pipe\n");
102 return STATUS_ILLEGAL_FUNCTION;
103 }
104
105 /* Fail, if the CCB is not a server end CCB */
106 if (Ccb->PipeEnd != FILE_PIPE_SERVER_END)
107 {
108 DPRINT1("Not the server end\n");
109 return STATUS_ILLEGAL_FUNCTION;
110 }
111
112 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
113 {
114 KeResetEvent(&Ccb->ConnectEvent);
115 return STATUS_PIPE_CONNECTED;
116 }
117
118 if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
119 return STATUS_PIPE_CLOSING;
120
121 DPRINT("Waiting for connection...\n");
122
123 Fcb = Ccb->Fcb;
124 IoStack = IoGetCurrentIrpStackLocation(Irp);
125 FileObject = IoStack->FileObject;
126 Flags = FileObject->Flags;
127
128 /* search for a listening client fcb */
129 KeLockMutex(&Fcb->CcbListLock);
130
131 current_entry = Fcb->ClientCcbListHead.Flink;
132 while (current_entry != &Fcb->ClientCcbListHead)
133 {
134 ClientCcb = CONTAINING_RECORD(current_entry,
135 NPFS_CCB,
136 CcbListEntry);
137
138 if (ClientCcb->PipeState == 0)
139 {
140 /* found a passive (waiting) client CCB */
141 DPRINT("Passive (waiting) client CCB found -- wake the client\n");
142 KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
143 break;
144 }
145
146 #if 0
147 if (ClientCcb->PipeState == FILE_PIPE_LISTENING_STATE)
148 {
149 /* found a listening client CCB */
150 DPRINT("Listening client CCB found -- connecting\n");
151
152 /* connect client and server CCBs */
153 Ccb->OtherSide = ClientCcb;
154 ClientCcb->OtherSide = Ccb;
155
156 /* set connected state */
157 Ccb->PipeState = FILE_PIPE_CONNECTED_STATE;
158 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
159
160 KeUnlockMutex(&Fcb->CcbListLock);
161
162 /* FIXME: create and initialize data queues */
163
164 /* signal client's connect event */
165 DPRINT("Setting the ConnectEvent for %x\n", ClientCcb);
166 KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
167
168 return STATUS_PIPE_CONNECTED;
169 }
170 #endif
171
172 current_entry = current_entry->Flink;
173 }
174
175 /* no listening client fcb found */
176 DPRINT("No listening client fcb found -- waiting for client\n");
177
178 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
179
180 Status = NpfsAddListeningServerInstance(Irp, Ccb);
181
182 KeUnlockMutex(&Fcb->CcbListLock);
183
184 if (Flags & FO_SYNCHRONOUS_IO)
185 {
186 KeWaitForSingleObject(&Ccb->ConnectEvent,
187 UserRequest,
188 Irp->RequestorMode,
189 FALSE,
190 NULL);
191 }
192
193 DPRINT("NpfsConnectPipe() done (Status %lx)\n", Status);
194
195 return Status;
196 }
197
198
199 static NTSTATUS
200 NpfsDisconnectPipe(PNPFS_CCB Ccb)
201 {
202 NTSTATUS Status;
203 PNPFS_FCB Fcb;
204 PNPFS_CCB OtherSide;
205 BOOLEAN Server;
206
207 DPRINT("NpfsDisconnectPipe()\n");
208
209 /* Fail, if the CCB is not a pipe CCB */
210 if (Ccb->Type != CCB_PIPE)
211 {
212 DPRINT1("Not a pipe\n");
213 return STATUS_ILLEGAL_FUNCTION;
214 }
215
216 /* Fail, if the CCB is not a server end CCB */
217 if (Ccb->PipeEnd != FILE_PIPE_SERVER_END)
218 {
219 DPRINT1("Not the server end\n");
220 return STATUS_ILLEGAL_FUNCTION;
221 }
222
223 Fcb = Ccb->Fcb;
224 KeLockMutex(&Fcb->CcbListLock);
225
226 if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
227 {
228 DPRINT("Pipe is already disconnected\n");
229 Status = STATUS_PIPE_DISCONNECTED;
230 }
231 else if ((!Ccb->OtherSide) && (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE))
232 {
233 ExAcquireFastMutex(&Ccb->DataListLock);
234 Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
235 ExReleaseFastMutex(&Ccb->DataListLock);
236 Status = STATUS_SUCCESS;
237 }
238 else if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
239 {
240 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
241 OtherSide = Ccb->OtherSide;
242 //Ccb->OtherSide = NULL;
243 Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
244 /* Lock the server first */
245 if (Server)
246 {
247 ExAcquireFastMutex(&Ccb->DataListLock);
248 ExAcquireFastMutex(&OtherSide->DataListLock);
249 }
250 else
251 {
252 ExAcquireFastMutex(&OtherSide->DataListLock);
253 ExAcquireFastMutex(&Ccb->DataListLock);
254 }
255 OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
256 //OtherSide->OtherSide = NULL;
257 /*
258 * Signaling the write event. If is possible that an other
259 * thread waits for an empty buffer.
260 */
261 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
262 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
263 if (Server)
264 {
265 ExReleaseFastMutex(&OtherSide->DataListLock);
266 ExReleaseFastMutex(&Ccb->DataListLock);
267 }
268 else
269 {
270 ExReleaseFastMutex(&Ccb->DataListLock);
271 ExReleaseFastMutex(&OtherSide->DataListLock);
272 }
273 Status = STATUS_SUCCESS;
274 }
275 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
276 {
277 PLIST_ENTRY Entry;
278 PNPFS_WAITER_ENTRY WaitEntry = NULL;
279 BOOLEAN Complete = FALSE;
280 PIRP Irp = NULL;
281
282 Entry = Ccb->Fcb->WaiterListHead.Flink;
283 while (Entry != &Ccb->Fcb->WaiterListHead)
284 {
285 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
286 if (WaitEntry->Ccb == Ccb)
287 {
288 RemoveEntryList(Entry);
289 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DriverContext);
290 Complete = (NULL == IoSetCancelRoutine(Irp, NULL));
291 break;
292 }
293 Entry = Entry->Flink;
294 }
295
296 if (Irp)
297 {
298 if (Complete)
299 {
300 Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
301 Irp->IoStatus.Information = 0;
302 IoCompleteRequest(Irp, IO_NO_INCREMENT);
303 }
304 }
305 Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
306 Status = STATUS_SUCCESS;
307 }
308 else if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
309 {
310 Status = STATUS_PIPE_CLOSING;
311 }
312 else
313 {
314 Status = STATUS_UNSUCCESSFUL;
315 }
316 KeUnlockMutex(&Fcb->CcbListLock);
317 return Status;
318 }
319
320
321 static NTSTATUS
322 NpfsWaitPipe(PIRP Irp,
323 PNPFS_CCB Ccb)
324 {
325 PLIST_ENTRY current_entry;
326 PNPFS_FCB Fcb;
327 PNPFS_CCB ServerCcb;
328 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
329 LARGE_INTEGER TimeOut;
330 NTSTATUS Status;
331 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
332 PNPFS_VCB Vcb;
333 UNICODE_STRING PipeName;
334 #endif
335
336 DPRINT("NpfsWaitPipe\n");
337
338 WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
339
340 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
341 /* Fail, if the CCB does not represent the root directory */
342 if (Ccb->Type != CCB_DIRECTORY)
343 return STATUS_ILLEGAL_FUNCTION;
344
345 /* Calculate the pipe name length and allocate the buffer */
346 PipeName.Length = WaitPipe->NameLength + sizeof(WCHAR);
347 PipeName.MaximumLength = PipeName.Length + sizeof(WCHAR);
348 PipeName.Buffer = ExAllocatePool(NonPagedPool, PipeName.MaximumLength);
349 if (PipeName.Buffer == NULL)
350 {
351 DPRINT1("Could not allocate memory for the pipe name!\n");
352 return STATUS_NO_MEMORY;
353 }
354
355 /* Copy the pipe name into the buffer, prepend a backslash and append a 0 character */
356 PipeName.Buffer[0] = L'\\';
357 RtlCopyMemory(&PipeName.Buffer[1],
358 &WaitPipe->Name[0],
359 WaitPipe->NameLength);
360 PipeName.Buffer[PipeName.Length / sizeof(WCHAR)] = 0;
361
362 DPRINT("Waiting for Pipe %wZ\n", &PipeName);
363
364 /* Get the VCB */
365 Vcb = Ccb->Fcb->Vcb;
366
367 /* Lock the pipe list */
368 KeLockMutex(&Vcb->PipeListLock);
369
370 /* File a pipe with the given name */
371 Fcb = NpfsFindPipe(Vcb,
372 &PipeName);
373
374 /* Unlock the pipe list */
375 KeUnlockMutex(&Vcb->PipeListLock);
376
377 /* Release the pipe name buffer */
378 ExFreePool(PipeName.Buffer);
379
380 /* Fail if not pipe was found */
381 if (Fcb == NULL)
382 {
383 DPRINT("No pipe found!\n", Fcb);
384 return STATUS_OBJECT_NAME_NOT_FOUND;
385 }
386
387 DPRINT("Fcb %p\n", Fcb);
388 #else
389 Fcb = Ccb->Fcb;
390
391 if (Ccb->PipeState != 0)
392 {
393 DPRINT("Pipe is not in passive (waiting) state!\n");
394 return STATUS_UNSUCCESSFUL;
395 }
396 #endif
397
398 /* search for listening server */
399 current_entry = Fcb->ServerCcbListHead.Flink;
400 while (current_entry != &Fcb->ServerCcbListHead)
401 {
402 ServerCcb = CONTAINING_RECORD(current_entry,
403 NPFS_CCB,
404 CcbListEntry);
405
406 if (ServerCcb->PipeState == FILE_PIPE_LISTENING_STATE)
407 {
408 /* found a listening server CCB */
409 DPRINT("Listening server CCB found -- connecting\n");
410
411 return STATUS_SUCCESS;
412 }
413
414 current_entry = current_entry->Flink;
415 }
416
417 /* No listening server fcb found */
418
419 /* If no timeout specified, use the default one */
420 if (WaitPipe->TimeoutSpecified)
421 TimeOut = WaitPipe->Timeout;
422 else
423 TimeOut = Fcb->TimeOut;
424
425 /* Wait for one */
426 Status = KeWaitForSingleObject(&Ccb->ConnectEvent,
427 UserRequest,
428 KernelMode,
429 FALSE,
430 &TimeOut);
431
432 DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status);
433
434 return Status;
435 }
436
437
438 /*
439 * FUNCTION: Return current state of a pipe
440 * ARGUMENTS:
441 * Irp = Pointer to I/O request packet
442 * IrpSp = Pointer to current stack location of Irp
443 * RETURNS:
444 * Status of operation
445 */
446
447 /*
448 * FUNCTION: Peek at a pipe (get information about messages)
449 * ARGUMENTS:
450 * Irp = Pointer to I/O request packet
451 * IoStack = Pointer to current stack location of Irp
452 * RETURNS:
453 * Status of operation
454 */
455 static NTSTATUS
456 NpfsPeekPipe(PIRP Irp,
457 PIO_STACK_LOCATION IoStack)
458 {
459 ULONG OutputBufferLength;
460 ULONG ReturnLength = 0;
461 PFILE_PIPE_PEEK_BUFFER Reply;
462 PNPFS_FCB Fcb;
463 PNPFS_CCB Ccb;
464 NTSTATUS Status;
465 ULONG MessageCount = 0;
466 ULONG MessageLength;
467 ULONG ReadDataAvailable;
468 PVOID BufferPtr;
469
470 DPRINT("NpfsPeekPipe\n");
471
472 OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
473 DPRINT("OutputBufferLength: %lu\n", OutputBufferLength);
474
475 /* Validate parameters */
476 if (OutputBufferLength < sizeof(FILE_PIPE_PEEK_BUFFER))
477 {
478 DPRINT1("Buffer too small\n");
479 return STATUS_INVALID_PARAMETER;
480 }
481
482 Ccb = IoStack->FileObject->FsContext2;
483 Reply = (PFILE_PIPE_PEEK_BUFFER)Irp->AssociatedIrp.SystemBuffer;
484 Fcb = Ccb->Fcb;
485
486
487 Reply->NamedPipeState = Ccb->PipeState;
488
489 Reply->ReadDataAvailable = Ccb->ReadDataAvailable;
490 DPRINT("ReadDataAvailable: %lu\n", Ccb->ReadDataAvailable);
491
492 ExAcquireFastMutex(&Ccb->DataListLock);
493 BufferPtr = Ccb->ReadPtr;
494 DPRINT("BufferPtr = %x\n", BufferPtr);
495 if (Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE)
496 {
497 DPRINT("Byte Stream Mode\n");
498 Reply->MessageLength = Ccb->ReadDataAvailable;
499 DPRINT("Reply->MessageLength %lu\n",Reply->MessageLength );
500 MessageCount = 1;
501
502 if (Reply->Data[0] && (OutputBufferLength >= Ccb->ReadDataAvailable + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])))
503 {
504 ReturnLength = Ccb->ReadDataAvailable;
505 memcpy(&Reply->Data[0], (PVOID)BufferPtr, Ccb->ReadDataAvailable);
506 }
507 }
508 else
509 {
510 DPRINT("Message Mode\n");
511 ReadDataAvailable=Ccb->ReadDataAvailable;
512
513 if (ReadDataAvailable > 0)
514 {
515 memcpy(&Reply->MessageLength, BufferPtr, sizeof(ULONG));
516
517 while ((ReadDataAvailable > 0) && (BufferPtr < Ccb->WritePtr))
518 {
519 memcpy(&MessageLength, BufferPtr, sizeof(MessageLength));
520
521 ASSERT(MessageLength > 0);
522
523 DPRINT("MessageLength = %lu\n",MessageLength);
524 ReadDataAvailable -= MessageLength;
525 MessageCount++;
526
527 /* If its the first message, copy the Message if the size of buffer is large enough */
528 if (MessageCount==1)
529 {
530 if ((Reply->Data[0])
531 && (OutputBufferLength >= (MessageLength + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]))))
532 {
533 memcpy(&Reply->Data[0], (PVOID)((ULONG_PTR)BufferPtr + sizeof(MessageLength)), MessageLength);
534 ReturnLength = MessageLength;
535 }
536 }
537
538 BufferPtr =(PVOID)((ULONG_PTR)BufferPtr + MessageLength + sizeof(MessageLength));
539 DPRINT("BufferPtr = %x\n", BufferPtr);
540 DPRINT("ReadDataAvailable: %lu\n", ReadDataAvailable);
541 }
542
543 if (ReadDataAvailable != 0)
544 {
545 DPRINT1("Possible memory corruption.\n");
546 ASSERT(FALSE);
547 }
548 }
549 }
550 ExReleaseFastMutex(&Ccb->DataListLock);
551
552 Reply->NumberOfMessages = MessageCount;
553
554 Irp->IoStatus.Information = ReturnLength + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
555 Irp->IoStatus.Status = STATUS_SUCCESS;
556
557 Status = STATUS_SUCCESS;
558
559 DPRINT("NpfsPeekPipe done\n");
560
561 return Status;
562 }
563
564
565 NTSTATUS NTAPI
566 NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
567 PIRP Irp)
568 {
569 PIO_STACK_LOCATION IoStack;
570 PFILE_OBJECT FileObject;
571 NTSTATUS Status;
572 PNPFS_VCB Vcb;
573 PNPFS_FCB Fcb;
574 PNPFS_CCB Ccb;
575
576 DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
577
578 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
579 IoStack = IoGetCurrentIrpStackLocation(Irp);
580 DPRINT("IoStack: %p\n", IoStack);
581 FileObject = IoStack->FileObject;
582 DPRINT("FileObject: %p\n", FileObject);
583 Ccb = FileObject->FsContext2;
584 DPRINT("CCB: %p\n", Ccb);
585 Fcb = Ccb->Fcb;
586 DPRINT("Pipe: %p\n", Fcb);
587 DPRINT("PipeName: %wZ\n", &Fcb->PipeName);
588
589 Irp->IoStatus.Information = 0;
590
591 switch (IoStack->Parameters.FileSystemControl.FsControlCode)
592 {
593 case FSCTL_PIPE_ASSIGN_EVENT:
594 DPRINT1("Assign event not implemented\n");
595 Status = STATUS_NOT_IMPLEMENTED;
596 break;
597
598 case FSCTL_PIPE_DISCONNECT:
599 DPRINT("Disconnecting pipe %wZ\n", &Fcb->PipeName);
600 Status = NpfsDisconnectPipe(Ccb);
601 break;
602
603 case FSCTL_PIPE_LISTEN:
604 DPRINT("Connecting pipe %wZ\n", &Fcb->PipeName);
605 Status = NpfsConnectPipe(Irp, Ccb);
606 break;
607
608 case FSCTL_PIPE_PEEK:
609 DPRINT("Peeking pipe %wZ\n", &Fcb->PipeName);
610 Status = NpfsPeekPipe(Irp, (PIO_STACK_LOCATION)IoStack);
611 break;
612
613 case FSCTL_PIPE_QUERY_EVENT:
614 DPRINT1("Query event not implemented\n");
615 Status = STATUS_NOT_IMPLEMENTED;
616 break;
617
618 case FSCTL_PIPE_TRANSCEIVE:
619 /* If you implement this, please remove the workaround in
620 lib/kernel32/file/npipe.c function TransactNamedPipe() */
621 DPRINT1("Transceive not implemented\n");
622 Status = STATUS_NOT_IMPLEMENTED;
623 break;
624
625 case FSCTL_PIPE_WAIT:
626 DPRINT("Waiting for pipe %wZ\n", &Fcb->PipeName);
627 Status = NpfsWaitPipe(Irp, Ccb);
628 break;
629
630 case FSCTL_PIPE_IMPERSONATE:
631 DPRINT1("Impersonate not implemented\n");
632 Status = STATUS_NOT_IMPLEMENTED;
633 break;
634
635 case FSCTL_PIPE_SET_CLIENT_PROCESS:
636 DPRINT1("Set client process not implemented\n");
637 Status = STATUS_NOT_IMPLEMENTED;
638 break;
639
640 case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
641 DPRINT1("Query client process not implemented\n");
642 Status = STATUS_NOT_IMPLEMENTED;
643 break;
644
645 case FSCTL_PIPE_INTERNAL_READ:
646 DPRINT1("Internal read not implemented\n");
647 Status = STATUS_NOT_IMPLEMENTED;
648 break;
649
650 case FSCTL_PIPE_INTERNAL_WRITE:
651 DPRINT1("Internal write not implemented\n");
652 Status = STATUS_NOT_IMPLEMENTED;
653 break;
654
655 case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
656 DPRINT1("Internal transceive not implemented\n");
657 Status = STATUS_NOT_IMPLEMENTED;
658 break;
659
660 case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
661 DPRINT1("Internal read overflow not implemented\n");
662 Status = STATUS_NOT_IMPLEMENTED;
663 break;
664
665 default:
666 DPRINT1("Unrecognized IoControlCode: %x\n",
667 IoStack->Parameters.FileSystemControl.FsControlCode);
668 Status = STATUS_UNSUCCESSFUL;
669 }
670
671 if (Status != STATUS_PENDING)
672 {
673 Irp->IoStatus.Status = Status;
674
675 IoCompleteRequest(Irp, IO_NO_INCREMENT);
676 }
677
678 return Status;
679 }
680
681
682 NTSTATUS NTAPI
683 NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject,
684 PIRP Irp)
685 {
686 /* FIXME: Implement */
687
688 Irp->IoStatus.Status = STATUS_SUCCESS;
689 Irp->IoStatus.Information = 0;
690
691 IoCompleteRequest(Irp, IO_NO_INCREMENT);
692
693 return STATUS_SUCCESS;
694 }
695
696 /* EOF */