- Fix calculation of WriteQuotaAvailable and WritePtr when moving memory.
[reactos.git] / reactos / drivers / filesystems / npfs / rw.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/rw.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
7 * Michael Martin
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "npfs.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 VOID HexDump(PUCHAR Buffer, ULONG Length)
20 {
21 CHAR Line[65];
22 UCHAR ch;
23 const char Hex[] = "0123456789ABCDEF";
24 int i, j;
25
26 DbgPrint("---------------\n");
27
28 for (i = 0; i < Length; i+= 16)
29 {
30 memset(Line, ' ', 64);
31 Line[64] = 0;
32
33 for (j = 0; j < 16 && j + i < Length; j++)
34 {
35 ch = Buffer[i + j];
36 Line[3*j + 0] = Hex[ch >> 4];
37 Line[3*j + 1] = Hex[ch & 0x0f];
38 Line[48 + j] = isprint(ch) ? ch : '.';
39 }
40 DbgPrint("%s\n", Line);
41 }
42 DbgPrint("---------------\n");
43 }
44
45 static DRIVER_CANCEL NpfsReadWriteCancelRoutine;
46 static VOID NTAPI
47 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP Irp)
49 {
50 PNPFS_CONTEXT Context;
51 PNPFS_DEVICE_EXTENSION DeviceExt;
52 PIO_STACK_LOCATION IoStack;
53 PNPFS_CCB Ccb;
54 BOOLEAN Complete = FALSE;
55
56 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
57
58 IoReleaseCancelSpinLock(Irp->CancelIrql);
59
60 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
61 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
62 IoStack = IoGetCurrentIrpStackLocation(Irp);
63 Ccb = IoStack->FileObject->FsContext2;
64
65 KeLockMutex(&DeviceExt->PipeListLock);
66 ExAcquireFastMutex(&Ccb->DataListLock);
67 switch(IoStack->MajorFunction)
68 {
69 case IRP_MJ_READ:
70 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
71 {
72 /* we are not the first in the list, remove an complete us */
73 RemoveEntryList(&Context->ListEntry);
74 Complete = TRUE;
75 }
76 else
77 {
78 KeSetEvent(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE);
79 }
80 break;
81 default:
82 ASSERT(FALSE);
83 }
84 ExReleaseFastMutex(&Ccb->DataListLock);
85 KeUnlockMutex(&DeviceExt->PipeListLock);
86 if (Complete)
87 {
88 Irp->IoStatus.Status = STATUS_CANCELLED;
89 Irp->IoStatus.Information = 0;
90 IoCompleteRequest(Irp, IO_NO_INCREMENT);
91 }
92 }
93
94 static VOID NTAPI
95 NpfsWaiterThread(PVOID InitContext)
96 {
97 PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
98 ULONG CurrentCount;
99 ULONG Count = 0;
100 PIRP Irp = NULL;
101 PIRP NextIrp;
102 NTSTATUS Status;
103 BOOLEAN Terminate = FALSE;
104 BOOLEAN Cancel = FALSE;
105 PIO_STACK_LOCATION IoStack = NULL;
106 PNPFS_CONTEXT Context;
107 PNPFS_CONTEXT NextContext;
108 PNPFS_CCB Ccb;
109
110 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
111
112 while (1)
113 {
114 CurrentCount = ThreadContext->Count;
115 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
116 if (Irp)
117 {
118 if (Cancel)
119 {
120 Irp->IoStatus.Status = STATUS_CANCELLED;
121 Irp->IoStatus.Information = 0;
122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
123 }
124 else
125 {
126 switch (IoStack->MajorFunction)
127 {
128 case IRP_MJ_READ:
129 NpfsRead(IoStack->DeviceObject, Irp);
130 break;
131 default:
132 ASSERT(FALSE);
133 }
134 }
135 }
136 if (Terminate)
137 {
138 break;
139 }
140 Status = KeWaitForMultipleObjects(CurrentCount,
141 ThreadContext->WaitObjectArray,
142 WaitAny,
143 Executive,
144 KernelMode,
145 FALSE,
146 NULL,
147 ThreadContext->WaitBlockArray);
148 if (!NT_SUCCESS(Status))
149 {
150 ASSERT(FALSE);
151 }
152 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
153 Count = Status - STATUS_SUCCESS;
154 ASSERT (Count < CurrentCount);
155 if (Count > 0)
156 {
157 Irp = ThreadContext->WaitIrpArray[Count];
158 ThreadContext->Count--;
159 ThreadContext->DeviceExt->EmptyWaiterCount++;
160 ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
161 ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
162
163 Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
164 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
165 IoStack = IoGetCurrentIrpStackLocation(Irp);
166
167 if (Cancel)
168 {
169 Ccb = IoStack->FileObject->FsContext2;
170 ExAcquireFastMutex(&Ccb->DataListLock);
171 RemoveEntryList(&Context->ListEntry);
172 switch (IoStack->MajorFunction)
173 {
174 case IRP_MJ_READ:
175 if (!IsListEmpty(&Ccb->ReadRequestListHead))
176 {
177 /* put the next request on the wait list */
178 NextContext = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
179 ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
180 NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
181 ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
182 ThreadContext->Count++;
183 ThreadContext->DeviceExt->EmptyWaiterCount--;
184 }
185 break;
186 default:
187 ASSERT(FALSE);
188 }
189 ExReleaseFastMutex(&Ccb->DataListLock);
190 }
191 }
192 else
193 {
194 /* someone has add a new wait request */
195 Irp = NULL;
196 }
197 if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
198 {
199 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
200 RemoveEntryList(&ThreadContext->ListEntry);
201 ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
202 Terminate = TRUE;
203 }
204 }
205 ExFreePool(ThreadContext);
206 }
207
208 static NTSTATUS
209 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
210 IN PIRP Irp)
211 {
212 PLIST_ENTRY ListEntry;
213 PNPFS_THREAD_CONTEXT ThreadContext = NULL;
214 NTSTATUS Status;
215 HANDLE hThread;
216 KIRQL oldIrql;
217
218 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
219 PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
220
221 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
222
223 KeLockMutex(&DeviceExt->PipeListLock);
224
225 ListEntry = DeviceExt->ThreadListHead.Flink;
226 while (ListEntry != &DeviceExt->ThreadListHead)
227 {
228 ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
229 if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
230 {
231 break;
232 }
233 ListEntry = ListEntry->Flink;
234 }
235 if (ListEntry == &DeviceExt->ThreadListHead)
236 {
237 ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
238 if (ThreadContext == NULL)
239 {
240 KeUnlockMutex(&DeviceExt->PipeListLock);
241 return STATUS_NO_MEMORY;
242 }
243 ThreadContext->DeviceExt = DeviceExt;
244 KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
245 ThreadContext->Count = 1;
246 ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
247
248
249 DPRINT("Creating a new system thread for waiting read/write requests\n");
250
251 Status = PsCreateSystemThread(&hThread,
252 THREAD_ALL_ACCESS,
253 NULL,
254 NULL,
255 NULL,
256 NpfsWaiterThread,
257 (PVOID)ThreadContext);
258 if (!NT_SUCCESS(Status))
259 {
260 ExFreePool(ThreadContext);
261 KeUnlockMutex(&DeviceExt->PipeListLock);
262 return Status;
263 }
264 InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
265 DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
266 }
267 IoMarkIrpPending(Irp);
268
269 IoAcquireCancelSpinLock(&oldIrql);
270 if (Irp->Cancel)
271 {
272 IoReleaseCancelSpinLock(oldIrql);
273 Status = STATUS_CANCELLED;
274 }
275 else
276 {
277 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
278 IoReleaseCancelSpinLock(oldIrql);
279 ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
280 ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
281 ThreadContext->Count++;
282 DeviceExt->EmptyWaiterCount--;
283 KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
284 Status = STATUS_SUCCESS;
285 }
286 KeUnlockMutex(&DeviceExt->PipeListLock);
287 return Status;
288 }
289
290 NTSTATUS NTAPI
291 NpfsRead(IN PDEVICE_OBJECT DeviceObject,
292 IN PIRP Irp)
293 {
294 PFILE_OBJECT FileObject;
295 NTSTATUS Status;
296 NTSTATUS OriginalStatus = STATUS_SUCCESS;
297 PNPFS_CCB Ccb;
298 PNPFS_CONTEXT Context;
299 KEVENT Event;
300 ULONG Length;
301 ULONG Information = 0;
302 ULONG CopyLength = 0;
303 ULONG TempLength;
304 BOOLEAN IsOriginalRequest = TRUE;
305 PVOID Buffer;
306
307 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
308
309 if (Irp->MdlAddress == NULL)
310 {
311 DPRINT("Irp->MdlAddress == NULL\n");
312 Status = STATUS_UNSUCCESSFUL;
313 Irp->IoStatus.Information = 0;
314 goto done;
315 }
316
317 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
318 DPRINT("FileObject %p\n", FileObject);
319 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
320 Ccb = FileObject->FsContext2;
321 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
322
323 if ((Ccb->OtherSide) && (Ccb->OtherSide->PipeState == FILE_PIPE_DISCONNECTED_STATE) && (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
324 {
325 DPRINT("Both Client and Server are disconnected!\n");
326 Status = STATUS_PIPE_DISCONNECTED;
327 Irp->IoStatus.Information = 0;
328 goto done;
329
330 }
331
332 if ((Ccb->OtherSide == NULL) && (Ccb->ReadDataAvailable == 0))
333 {
334 /* Its ok if the other side has been Disconnect, but if we have data still in the buffer
335 , need to still be able to read it. Currently this is a HAXXXX */
336 DPRINT("Pipe no longer connected and no data exist in buffer. Ok to close pipe\n");
337 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
338 Status = STATUS_PIPE_LISTENING;
339 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
340 Status = STATUS_PIPE_DISCONNECTED;
341 else
342 Status = STATUS_UNSUCCESSFUL;
343 Irp->IoStatus.Information = 0;
344 goto done;
345 }
346
347 if (Ccb->Data == NULL)
348 {
349 DPRINT1("Pipe is NOT readable!\n");
350 Status = STATUS_UNSUCCESSFUL;
351 Irp->IoStatus.Information = 0;
352 goto done;
353 }
354
355 ExAcquireFastMutex(&Ccb->DataListLock);
356
357 if (IoIsOperationSynchronous(Irp))
358 {
359 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
360 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
361 {
362 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
363 Context->WaitEvent = &Event;
364 ExReleaseFastMutex(&Ccb->DataListLock);
365 Status = KeWaitForSingleObject(&Event,
366 Executive,
367 Irp->RequestorMode,
368 FALSE,
369 NULL);
370 if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC))
371 {
372 Status = STATUS_CANCELLED;
373 goto done;
374 }
375 if (!NT_SUCCESS(Status))
376 {
377 ASSERT(FALSE);
378 }
379 ExAcquireFastMutex(&Ccb->DataListLock);
380 }
381 Irp->IoStatus.Information = 0;
382 }
383 else
384 {
385 KIRQL oldIrql;
386 if (IsListEmpty(&Ccb->ReadRequestListHead) ||
387 Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
388 {
389 /* this is a new request */
390 Irp->IoStatus.Information = 0;
391 Context->WaitEvent = &Ccb->ReadEvent;
392 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
393 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
394 {
395 /* there was already a request on the list */
396 IoAcquireCancelSpinLock(&oldIrql);
397 if (Irp->Cancel)
398 {
399 IoReleaseCancelSpinLock(oldIrql);
400 RemoveEntryList(&Context->ListEntry);
401 ExReleaseFastMutex(&Ccb->DataListLock);
402 Status = STATUS_CANCELLED;
403 goto done;
404 }
405 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
406 IoReleaseCancelSpinLock(oldIrql);
407 ExReleaseFastMutex(&Ccb->DataListLock);
408 IoMarkIrpPending(Irp);
409 Status = STATUS_PENDING;
410 goto done;
411 }
412 }
413 }
414
415 while (1)
416 {
417 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
418 Information = Irp->IoStatus.Information;
419 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
420 ASSERT (Information <= Length);
421 Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
422 Length -= Information;
423 Status = STATUS_SUCCESS;
424
425 while (1)
426 {
427 if (Ccb->ReadDataAvailable == 0)
428 {
429 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
430 {
431 ASSERT(Ccb->OtherSide != NULL);
432 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
433 }
434 if (Information > 0 &&
435 (Ccb->Fcb->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
436 Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
437 {
438 break;
439 }
440 if ((Ccb->PipeState != FILE_PIPE_CONNECTED_STATE) && (Ccb->ReadDataAvailable == 0))
441 {
442 DPRINT("PipeState: %x\n", Ccb->PipeState);
443 Status = STATUS_PIPE_BROKEN;
444 break;
445 }
446 ExReleaseFastMutex(&Ccb->DataListLock);
447
448 if (IoIsOperationSynchronous(Irp))
449 {
450 /* Wait for ReadEvent to become signaled */
451
452 DPRINT("Waiting for readable data (%wZ)\n", &Ccb->Fcb->PipeName);
453 Status = KeWaitForSingleObject(&Ccb->ReadEvent,
454 UserRequest,
455 Irp->RequestorMode,
456 FALSE,
457 NULL);
458 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
459
460 if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC))
461 {
462 Status = STATUS_CANCELLED;
463 break;
464 }
465 if (!NT_SUCCESS(Status))
466 {
467 ASSERT(FALSE);
468 }
469 ExAcquireFastMutex(&Ccb->DataListLock);
470 }
471 else
472 {
473 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
474
475 Context->WaitEvent = &Ccb->ReadEvent;
476
477 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
478
479 if (NT_SUCCESS(Status))
480 {
481 Status = STATUS_PENDING;
482 goto done;
483 }
484 ExAcquireFastMutex(&Ccb->DataListLock);
485 break;
486 }
487 }
488 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
489
490 /* If the pipe type and read mode are both byte stream */
491 if ((Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE) && (Ccb->Fcb->ReadMode == FILE_PIPE_BYTE_STREAM_MODE))
492 {
493 DPRINT("Byte stream mode: Ccb->Data %x\n", Ccb->Data);
494 /* Byte stream mode */
495 while (Length > 0 && Ccb->ReadDataAvailable > 0)
496 {
497 CopyLength = min(Ccb->ReadDataAvailable, Length);
498 if ((ULONG_PTR)Ccb->ReadPtr + CopyLength <= (ULONG_PTR)Ccb->Data + Ccb->MaxDataLength)
499 {
500 memcpy(Buffer, Ccb->ReadPtr, CopyLength);
501 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
502 if (Ccb->ReadPtr == (PVOID)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength))
503 {
504 Ccb->ReadPtr = Ccb->Data;
505 }
506 }
507 else
508 {
509 TempLength = (ULONG)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength - (ULONG_PTR)Ccb->ReadPtr);
510 memcpy(Buffer, Ccb->ReadPtr, TempLength);
511 memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Ccb->Data, CopyLength - TempLength);
512 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->Data + CopyLength - TempLength);
513 }
514
515 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
516 Length -= CopyLength;
517 Information += CopyLength;
518
519 Ccb->ReadDataAvailable -= CopyLength;
520 Ccb->WriteQuotaAvailable += CopyLength;
521 }
522
523 if ((Length == 0) || (Ccb->ReadDataAvailable == 0))
524 {
525 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
526 {
527 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
528 }
529 KeResetEvent(&Ccb->ReadEvent);
530 break;
531 }
532 }
533 else if (Ccb->Fcb->PipeType == FILE_PIPE_MESSAGE_TYPE)
534 {
535 DPRINT("Message mode: Ccb>Data %x\n", Ccb->Data);
536
537 /* Check if buffer is full and the read pointer is not at the start of the buffer */
538 if ((Ccb->WriteQuotaAvailable == 0) && (Ccb->ReadPtr > Ccb->Data))
539 {
540 Ccb->WriteQuotaAvailable += (ULONG_PTR)Ccb->ReadPtr - (ULONG_PTR)Ccb->Data;
541 memcpy(Ccb->Data, Ccb->ReadPtr, (ULONG_PTR)Ccb->WritePtr - (ULONG_PTR)Ccb->ReadPtr);
542 Ccb->WritePtr = (PVOID)((ULONG_PTR)Ccb->WritePtr - ((ULONG_PTR)Ccb->ReadPtr - (ULONG_PTR)Ccb->Data));
543 Ccb->ReadPtr = Ccb->Data;
544 }
545
546 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
547 if (Ccb->ReadDataAvailable)
548 {
549 ULONG NextMessageLength = 0;
550
551 /*First get the size of the message */
552 memcpy(&NextMessageLength, Ccb->ReadPtr, sizeof(NextMessageLength));
553
554 if ((NextMessageLength == 0) || (NextMessageLength > Ccb->ReadDataAvailable))
555 {
556 DPRINT1("Possible memory corruption.\n");
557 HexDump(Ccb->Data, (ULONG_PTR)Ccb->WritePtr - (ULONG_PTR)Ccb->Data);
558 ASSERT(FALSE);
559 }
560
561 /* Use the smaller value */
562 CopyLength = min(NextMessageLength, Length);
563 ASSERT(CopyLength > 0);
564 ASSERT(CopyLength <= Ccb->ReadDataAvailable);
565 /* retrieve the message from the buffer */
566 memcpy(Buffer, (PVOID)((ULONG_PTR)Ccb->ReadPtr + sizeof(NextMessageLength)), CopyLength);
567
568 if (Ccb->ReadDataAvailable > CopyLength)
569 {
570 if (CopyLength < NextMessageLength)
571 /* Client only requested part of the message */
572 {
573 /* Calculate the remaining message new size */
574 ULONG NewMessageSize = NextMessageLength-CopyLength;
575
576 /* Update ReadPtr to point to new Message size location */
577 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
578
579 /* Write a new Message size to buffer for the part of the message still there */
580 memcpy(Ccb->ReadPtr, &NewMessageSize, sizeof(NewMessageSize));
581 }
582 else
583 /* Client wanted the entire message */
584 {
585 /* Update ReadPtr to point to next message size */
586 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength + sizeof(CopyLength));
587 }
588 }
589 else
590 {
591 /* This was the last Message, so just zero start of buffer for safety sake */
592 memset(Ccb->Data, 0, NextMessageLength + sizeof(NextMessageLength));
593
594 /* Reset to MaxDataLength as partial message retrievals dont
595 give the length back to Quota */
596 Ccb->WriteQuotaAvailable = Ccb->MaxDataLength;
597
598 /* reset read and write pointer to beginning of buffer */
599 Ccb->WritePtr = Ccb->Data;
600 Ccb->ReadPtr = Ccb->Data;
601 }
602 #ifndef NDEBUG
603 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
604 HexDump((PUCHAR)Buffer, CopyLength);
605 #endif
606
607 Information += CopyLength;
608
609 Ccb->ReadDataAvailable -= CopyLength;
610
611 if ((ULONG)Ccb->WriteQuotaAvailable > (ULONG)Ccb->MaxDataLength) ASSERT(FALSE);
612 }
613
614 if (Information > 0)
615 {
616 if ((Ccb->Fcb->ReadMode == FILE_PIPE_BYTE_STREAM_MODE) && (Ccb->ReadDataAvailable) && (Length > CopyLength))
617 {
618 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
619 Length -= CopyLength;
620 }
621 else
622 {
623 KeResetEvent(&Ccb->ReadEvent);
624
625 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->WriteQuotaAvailable > 0))
626 {
627 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
628 }
629 break;
630 }
631 }
632 }
633 else
634 {
635 DPRINT1("Unhandled Pipe Mode!\n");
636 ASSERT(FALSE);
637 }
638 }
639 Irp->IoStatus.Information = Information;
640 Irp->IoStatus.Status = Status;
641
642 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
643
644 if (Status == STATUS_CANCELLED)
645 goto done;
646
647 if (IoIsOperationSynchronous(Irp))
648 {
649 RemoveEntryList(&Context->ListEntry);
650 if (!IsListEmpty(&Ccb->ReadRequestListHead))
651 {
652 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
653 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
654 }
655 ExReleaseFastMutex(&Ccb->DataListLock);
656 IoCompleteRequest(Irp, IO_NO_INCREMENT);
657
658 DPRINT("NpfsRead done (Status %lx)\n", Status);
659 return Status;
660 }
661 else
662 {
663 if (IsOriginalRequest)
664 {
665 IsOriginalRequest = FALSE;
666 OriginalStatus = Status;
667 }
668 if (Status == STATUS_PENDING)
669 {
670 ExReleaseFastMutex(&Ccb->DataListLock);
671 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
672 return OriginalStatus;
673 }
674 RemoveEntryList(&Context->ListEntry);
675 IoCompleteRequest(Irp, IO_NO_INCREMENT);
676 if (IsListEmpty(&Ccb->ReadRequestListHead))
677 {
678 ExReleaseFastMutex(&Ccb->DataListLock);
679 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
680 return OriginalStatus;
681 }
682 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
683 Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
684 }
685 }
686
687 done:
688 Irp->IoStatus.Status = Status;
689
690 if (Status != STATUS_PENDING)
691 {
692 IoCompleteRequest(Irp, IO_NO_INCREMENT);
693 }
694 DPRINT("NpfsRead done (Status %lx)\n", Status);
695
696 return Status;
697 }
698
699 NTSTATUS NTAPI
700 NpfsWrite(PDEVICE_OBJECT DeviceObject,
701 PIRP Irp)
702 {
703 PIO_STACK_LOCATION IoStack;
704 PFILE_OBJECT FileObject;
705 PNPFS_FCB Fcb = NULL;
706 PNPFS_CCB Ccb = NULL;
707 PNPFS_CCB ReaderCcb;
708 PUCHAR Buffer;
709 NTSTATUS Status = STATUS_SUCCESS;
710 ULONG Length;
711 ULONG Offset;
712 ULONG Information;
713 ULONG CopyLength;
714 ULONG TempLength;
715
716 DPRINT("NpfsWrite()\n");
717
718 IoStack = IoGetCurrentIrpStackLocation(Irp);
719 FileObject = IoStack->FileObject;
720 DPRINT("FileObject %p\n", FileObject);
721 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
722
723 Ccb = FileObject->FsContext2;
724 ReaderCcb = Ccb->OtherSide;
725 Fcb = Ccb->Fcb;
726
727 Length = IoStack->Parameters.Write.Length;
728 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
729 Information = 0;
730
731 if (Irp->MdlAddress == NULL)
732 {
733 DPRINT("Irp->MdlAddress == NULL\n");
734 Status = STATUS_UNSUCCESSFUL;
735 Length = 0;
736 goto done;
737 }
738
739 if ((ReaderCcb == NULL) || (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
740 {
741 DPRINT("Pipe is NOT connected!\n");
742 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
743 Status = STATUS_PIPE_LISTENING;
744 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
745 Status = STATUS_PIPE_DISCONNECTED;
746 else
747 Status = STATUS_UNSUCCESSFUL;
748 Length = 0;
749 goto done;
750 }
751
752 if (ReaderCcb->Data == NULL)
753 {
754 DPRINT("Pipe is NOT writable!\n");
755 Status = STATUS_UNSUCCESSFUL;
756 Length = 0;
757 goto done;
758 }
759
760 Status = STATUS_SUCCESS;
761 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
762
763 ExAcquireFastMutex(&ReaderCcb->DataListLock);
764
765 #ifndef NDEBUG
766 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
767 HexDump(Buffer, Length);
768 #endif
769
770 while(1)
771 {
772 if ((ReaderCcb->WriteQuotaAvailable == 0))
773 {
774 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
775 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
776 {
777 Status = STATUS_PIPE_BROKEN;
778 ExReleaseFastMutex(&ReaderCcb->DataListLock);
779 goto done;
780 }
781 ExReleaseFastMutex(&ReaderCcb->DataListLock);
782
783 DPRINT("Write Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
784 Status = KeWaitForSingleObject(&Ccb->WriteEvent,
785 UserRequest,
786 Irp->RequestorMode,
787 FALSE,
788 NULL);
789 DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status);
790
791 if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC))
792 {
793 Status = STATUS_CANCELLED;
794 break;
795 }
796 if (!NT_SUCCESS(Status))
797 {
798 ASSERT(FALSE);
799 }
800 /*
801 * It's possible that the event was signaled because the
802 * other side of pipe was closed.
803 */
804 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
805 {
806 DPRINT("PipeState: %x\n", Ccb->PipeState);
807 Status = STATUS_PIPE_BROKEN;
808 goto done;
809 }
810 ExAcquireFastMutex(&ReaderCcb->DataListLock);
811 }
812
813 if ((Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE) && (Ccb->Fcb->WriteMode == FILE_PIPE_BYTE_STREAM_MODE))
814 {
815 DPRINT("Byte stream mode: Ccb->Data %x, Ccb->WritePtr %x\n", ReaderCcb->Data, ReaderCcb->WritePtr);
816
817 while (Length > 0 && ReaderCcb->WriteQuotaAvailable > 0)
818 {
819 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
820
821 if ((ULONG_PTR)ReaderCcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
822 {
823 memcpy(ReaderCcb->WritePtr, Buffer, CopyLength);
824 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + CopyLength);
825 if ((ULONG_PTR)ReaderCcb->WritePtr == (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
826 {
827 ReaderCcb->WritePtr = ReaderCcb->Data;
828 }
829 }
830 else
831 {
832
833 TempLength = (ULONG)((ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength -
834 (ULONG_PTR)ReaderCcb->WritePtr);
835
836 memcpy(ReaderCcb->WritePtr, Buffer, TempLength);
837 memcpy(ReaderCcb->Data, Buffer + TempLength, CopyLength - TempLength);
838 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->Data + CopyLength - TempLength);
839 }
840
841 Buffer += CopyLength;
842 Length -= CopyLength;
843 Information += CopyLength;
844
845 ReaderCcb->ReadDataAvailable += CopyLength;
846 ReaderCcb->WriteQuotaAvailable -= CopyLength;
847 }
848
849 if (Length == 0)
850 {
851 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
852 KeResetEvent(&Ccb->WriteEvent);
853 break;
854 }
855 }
856 else if ((Ccb->Fcb->PipeType == FILE_PIPE_MESSAGE_TYPE) && (Ccb->Fcb->WriteMode == FILE_PIPE_MESSAGE_MODE))
857 {
858 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
859 DPRINT("Message mode: Ccb->Data %x, Ccb->WritePtr %x\n",ReaderCcb->Data, ReaderCcb->WritePtr);
860 if (Length > 0)
861 {
862 /* Verify the WritePtr is still inside the buffer */
863 if (((ULONG_PTR)ReaderCcb->WritePtr > ((ULONG_PTR)ReaderCcb->Data + (ULONG_PTR)ReaderCcb->MaxDataLength)) ||
864 ((ULONG_PTR)ReaderCcb->WritePtr < (ULONG_PTR)ReaderCcb->Data))
865 {
866 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
867 DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength %lu\n",
868 ReaderCcb->WritePtr, ReaderCcb->Data, ReaderCcb->MaxDataLength);
869 ASSERT(FALSE);
870 }
871
872 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable - sizeof(ULONG));
873 if (CopyLength > ReaderCcb->WriteQuotaAvailable)
874 {
875 DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
876 CopyLength, ReaderCcb->WriteQuotaAvailable);
877 ASSERT(FALSE);
878 }
879
880 /* First Copy the Length of the message into the pipes buffer */
881 memcpy(ReaderCcb->WritePtr, &CopyLength, sizeof(CopyLength));
882
883 /* Now the user buffer itself */
884 memcpy((PVOID)((ULONG_PTR)ReaderCcb->WritePtr + sizeof(CopyLength)), Buffer, CopyLength);
885
886 /* Update the write pointer */
887 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + sizeof(CopyLength) + CopyLength);
888
889 Information += CopyLength;
890
891 ReaderCcb->ReadDataAvailable += CopyLength;
892
893 ReaderCcb->WriteQuotaAvailable -= (CopyLength + sizeof(ULONG));
894
895 if ((ULONG_PTR)ReaderCcb->WriteQuotaAvailable > (ULONG)ReaderCcb->MaxDataLength)
896 {
897 DPRINT1("QuotaAvailable is greater than buffer size!\n");
898 ASSERT(FALSE);
899 }
900 }
901
902 if (Information > 0)
903 {
904 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
905 KeResetEvent(&Ccb->WriteEvent);
906 break;
907 }
908 }
909 else
910 {
911 DPRINT1("Unhandled Pipe Type Mode and Read Write Mode!\n");
912 ASSERT(FALSE);
913 }
914 }
915
916 ExReleaseFastMutex(&ReaderCcb->DataListLock);
917
918 done:
919 Irp->IoStatus.Status = Status;
920 Irp->IoStatus.Information = Information;
921
922 IoCompleteRequest(Irp, IO_NO_INCREMENT);
923
924 DPRINT("NpfsWrite done (Status %lx)\n", Status);
925
926 return Status;
927 }
928
929 /* EOF */