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