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