ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rw.c
Go to the documentation of this file.
00001 /*
00002 * COPYRIGHT:  See COPYING in the top level directory
00003 * PROJECT:    ReactOS kernel
00004 * FILE:       drivers/fs/np/rw.c
00005 * PURPOSE:    Named pipe filesystem
00006 * PROGRAMMER: David Welch <welch@cwcom.net>
00007 *             Michael Martin
00008 */
00009 
00010 /* INCLUDES ******************************************************************/
00011 
00012 #include "npfs.h"
00013 
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 /* FUNCTIONS *****************************************************************/
00018 
00019 VOID HexDump(PUCHAR Buffer, ULONG Length)
00020 {
00021     CHAR Line[65];
00022     UCHAR ch;
00023     const char Hex[] = "0123456789ABCDEF";
00024     ULONG i, j;
00025 
00026     DbgPrint("---------------\n");
00027 
00028     for (i = 0; i < Length; i+= 16)
00029     {
00030         memset(Line, ' ', 64);
00031         Line[64] = 0;
00032 
00033         for (j = 0; j < 16 && j + i < Length; j++)
00034         {
00035             ch = Buffer[i + j];
00036             Line[3*j + 0] = Hex[ch >> 4];
00037             Line[3*j + 1] = Hex[ch & 0x0f];
00038             Line[48 + j] = isprint(ch) ? ch : '.';
00039         }
00040         DbgPrint("%s\n", Line);
00041     }
00042     DbgPrint("---------------\n");
00043 }
00044 
00045 static DRIVER_CANCEL NpfsReadWriteCancelRoutine;
00046 static VOID NTAPI
00047 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
00048                            IN PIRP Irp)
00049 {
00050     PNPFS_CONTEXT Context;
00051     PIO_STACK_LOCATION IoStack;
00052     PNPFS_VCB Vcb;
00053     PNPFS_CCB Ccb;
00054     PLIST_ENTRY ListEntry;
00055     PNPFS_THREAD_CONTEXT ThreadContext;
00056     ULONG i;
00057 
00058     DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
00059 
00060     IoReleaseCancelSpinLock(Irp->CancelIrql);
00061 
00062     Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
00063     Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
00064     IoStack = IoGetCurrentIrpStackLocation(Irp);
00065     Ccb = IoStack->FileObject->FsContext2;
00066 
00067     KeLockMutex(&Vcb->PipeListLock);
00068     ExAcquireFastMutex(&Ccb->DataListLock);
00069     switch(IoStack->MajorFunction)
00070     {
00071     case IRP_MJ_READ:
00072         ListEntry = Vcb->ThreadListHead.Flink;
00073         while (ListEntry != &Vcb->ThreadListHead)
00074         {
00075             ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
00076             /* Real events start at index 1 */
00077             for (i = 1; i < ThreadContext->Count; i++)
00078             {
00079                 if (ThreadContext->WaitIrpArray[i] == Irp)
00080                 {
00081                     ASSERT(ThreadContext->WaitObjectArray[i] == Context->WaitEvent);
00082 
00083                     ThreadContext->WaitIrpArray[i] = NULL;
00084 
00085                     RemoveEntryList(&Context->ListEntry);
00086 
00087                     Irp->IoStatus.Status = STATUS_CANCELLED;
00088                     Irp->IoStatus.Information = 0;
00089 
00090                     IoCompleteRequest(Irp, IO_NO_INCREMENT);
00091 
00092                     KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
00093 
00094                     ExReleaseFastMutex(&Ccb->DataListLock);
00095                     KeUnlockMutex(&Vcb->PipeListLock);
00096 
00097                     return;
00098                 }
00099             }
00100             ListEntry = ListEntry->Flink;
00101         }
00102 
00103         RemoveEntryList(&Context->ListEntry);
00104 
00105         ExReleaseFastMutex(&Ccb->DataListLock);
00106         KeUnlockMutex(&Vcb->PipeListLock);
00107 
00108         Irp->IoStatus.Status = STATUS_CANCELLED;
00109         Irp->IoStatus.Information = 0;
00110 
00111         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00112         break;
00113     default:
00114         ASSERT(FALSE);
00115     }
00116 }
00117 
00118 static VOID NTAPI
00119 NpfsWaiterThread(PVOID InitContext)
00120 {
00121     PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
00122     ULONG CurrentCount;
00123     ULONG Count = 0, i;
00124     PIRP Irp = NULL;
00125     NTSTATUS Status;
00126     PIO_STACK_LOCATION IoStack = NULL;
00127     KIRQL OldIrql;
00128 
00129     KeLockMutex(&ThreadContext->Vcb->PipeListLock);
00130 
00131     while (1)
00132     {
00133         CurrentCount = ThreadContext->Count;
00134         KeUnlockMutex(&ThreadContext->Vcb->PipeListLock);
00135         IoAcquireCancelSpinLock(&OldIrql);
00136         if (Irp && IoSetCancelRoutine(Irp, NULL) != NULL)
00137         {
00138             IoReleaseCancelSpinLock(OldIrql);
00139             IoStack = IoGetCurrentIrpStackLocation(Irp);
00140             switch (IoStack->MajorFunction)
00141             {
00142                 case IRP_MJ_READ:
00143                     NpfsRead(IoStack->DeviceObject, Irp);
00144                     break;
00145                 default:
00146                     ASSERT(FALSE);
00147             }
00148         }
00149         else
00150         {
00151             IoReleaseCancelSpinLock(OldIrql);
00152         }
00153         Status = KeWaitForMultipleObjects(CurrentCount,
00154             ThreadContext->WaitObjectArray,
00155             WaitAny,
00156             Executive,
00157             KernelMode,
00158             FALSE,
00159             NULL,
00160             ThreadContext->WaitBlockArray);
00161         if (!NT_SUCCESS(Status))
00162         {
00163             ASSERT(FALSE);
00164         }
00165         KeLockMutex(&ThreadContext->Vcb->PipeListLock);
00166         Count = Status - STATUS_WAIT_0;
00167         ASSERT (Count < CurrentCount);
00168         if (Count > 0)
00169         {
00170             Irp = ThreadContext->WaitIrpArray[Count];
00171             ThreadContext->Count--;
00172             ThreadContext->Vcb->EmptyWaiterCount++;
00173             ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
00174             ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
00175         }
00176         else
00177         {
00178             /* someone has add a new wait request or cancelled an old one */
00179             Irp = NULL;
00180 
00181             /* Look for cancelled requests */
00182             for (i = 1; i < ThreadContext->Count; i++)
00183             {
00184                 if (ThreadContext->WaitIrpArray[i] == NULL)
00185                 {
00186                    ThreadContext->Count--;
00187                    ThreadContext->Vcb->EmptyWaiterCount++;
00188                    ThreadContext->WaitObjectArray[i] = ThreadContext->WaitObjectArray[ThreadContext->Count];
00189                    ThreadContext->WaitIrpArray[i] = ThreadContext->WaitIrpArray[ThreadContext->Count];
00190                 }
00191             }
00192         }
00193         if (ThreadContext->Count == 1 && ThreadContext->Vcb->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
00194         {
00195             /* it exist an other thread with empty wait slots, we can remove our thread from the list */
00196             RemoveEntryList(&ThreadContext->ListEntry);
00197             ExFreePoolWithTag(ThreadContext, TAG_NPFS_THREAD_CONTEXT);
00198             KeUnlockMutex(&ThreadContext->Vcb->PipeListLock);
00199             break;
00200         }
00201     }
00202 }
00203 
00204 static NTSTATUS
00205 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
00206                                IN PIRP Irp)
00207 {
00208     PLIST_ENTRY ListEntry;
00209     PNPFS_THREAD_CONTEXT ThreadContext = NULL;
00210     PNPFS_CONTEXT Context;
00211     HANDLE hThread;
00212     PNPFS_VCB Vcb;
00213     KIRQL oldIrql;
00214     NTSTATUS Status;
00215 
00216     Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
00217     Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
00218 
00219     DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
00220 
00221     KeLockMutex(&Vcb->PipeListLock);
00222 
00223     ListEntry = Vcb->ThreadListHead.Flink;
00224     while (ListEntry != &Vcb->ThreadListHead)
00225     {
00226         ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
00227         if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
00228         {
00229             break;
00230         }
00231         ListEntry = ListEntry->Flink;
00232     }
00233 
00234     if (ListEntry == &Vcb->ThreadListHead)
00235     {
00236         ThreadContext = ExAllocatePoolWithTag(NonPagedPool,
00237                                               sizeof(NPFS_THREAD_CONTEXT),
00238                                               TAG_NPFS_THREAD_CONTEXT);
00239         if (ThreadContext == NULL)
00240         {
00241             KeUnlockMutex(&Vcb->PipeListLock);
00242             return STATUS_NO_MEMORY;
00243         }
00244 
00245         ThreadContext->Vcb = Vcb;
00246         KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
00247         ThreadContext->Count = 1;
00248         ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
00249 
00250         DPRINT("Creating a new system thread for waiting read/write requests\n");
00251 
00252         Status = PsCreateSystemThread(&hThread,
00253             THREAD_ALL_ACCESS,
00254             NULL,
00255             NULL,
00256             NULL,
00257             NpfsWaiterThread,
00258             (PVOID)ThreadContext);
00259         if (!NT_SUCCESS(Status))
00260         {
00261             ExFreePoolWithTag(ThreadContext, TAG_NPFS_THREAD_CONTEXT);
00262             KeUnlockMutex(&Vcb->PipeListLock);
00263             return Status;
00264         }
00265 
00266         InsertHeadList(&Vcb->ThreadListHead, &ThreadContext->ListEntry);
00267         Vcb->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
00268     }
00269     IoMarkIrpPending(Irp);
00270 
00271     IoAcquireCancelSpinLock(&oldIrql);
00272     if (Irp->Cancel)
00273     {
00274         IoReleaseCancelSpinLock(oldIrql);
00275         Status = STATUS_CANCELLED;
00276     }
00277     else
00278     {
00279         (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
00280         IoReleaseCancelSpinLock(oldIrql);
00281         ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
00282         ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
00283         ThreadContext->Count++;
00284         Vcb->EmptyWaiterCount--;
00285         KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
00286         Status = STATUS_SUCCESS;
00287     }
00288     KeUnlockMutex(&Vcb->PipeListLock);
00289     return Status;
00290 }
00291 
00292 NTSTATUS NTAPI
00293 NpfsRead(IN PDEVICE_OBJECT DeviceObject,
00294          IN PIRP Irp)
00295 {
00296     PFILE_OBJECT FileObject;
00297     NTSTATUS Status;
00298     NTSTATUS OriginalStatus = STATUS_SUCCESS;
00299     PNPFS_CCB Ccb;
00300     PNPFS_CONTEXT Context;
00301     KEVENT Event;
00302     ULONG Length;
00303     ULONG Information = 0;
00304     ULONG CopyLength = 0;
00305     ULONG TempLength;
00306     BOOLEAN IsOriginalRequest = TRUE;
00307     PVOID Buffer;
00308 
00309     DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
00310 
00311     FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
00312     DPRINT("FileObject %p\n", FileObject);
00313     DPRINT("Pipe name %wZ\n", &FileObject->FileName);
00314     Ccb = FileObject->FsContext2;
00315 
00316     /* Fail, if the CCB is not a pipe CCB */
00317     if (Ccb->Type != CCB_PIPE)
00318     {
00319         DPRINT("Not a pipe!\n");
00320         Status = STATUS_INVALID_PARAMETER;
00321         Irp->IoStatus.Information = 0;
00322         goto done;
00323     }
00324 
00325     if (Irp->MdlAddress == NULL)
00326     {
00327         DPRINT("Irp->MdlAddress == NULL\n");
00328         Status = STATUS_UNSUCCESSFUL;
00329         Irp->IoStatus.Information = 0;
00330         goto done;
00331     }
00332 
00333     Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
00334 
00335     if ((Ccb->OtherSide) && (Ccb->OtherSide->PipeState == FILE_PIPE_DISCONNECTED_STATE) && (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
00336     {
00337         DPRINT("Both Client and Server are disconnected!\n");
00338         Status = STATUS_PIPE_DISCONNECTED;
00339         Irp->IoStatus.Information = 0;
00340         goto done;
00341 
00342     }
00343 
00344     if ((Ccb->OtherSide == NULL) && (Ccb->ReadDataAvailable == 0))
00345     {
00346         if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
00347             Status = STATUS_PIPE_BROKEN;
00348         else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
00349             Status = STATUS_PIPE_LISTENING;
00350         else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
00351             Status = STATUS_PIPE_DISCONNECTED;
00352         else
00353             Status = STATUS_UNSUCCESSFUL;
00354         Irp->IoStatus.Information = 0;
00355         goto done;
00356     }
00357 
00358     if (Ccb->Data == NULL)
00359     {
00360         DPRINT("Pipe is NOT readable!\n");
00361         Status = STATUS_UNSUCCESSFUL;
00362         Irp->IoStatus.Information = 0;
00363         goto done;
00364     }
00365 
00366     ExAcquireFastMutex(&Ccb->DataListLock);
00367 
00368     if (IoIsOperationSynchronous(Irp))
00369     {
00370         InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
00371         if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
00372         {
00373             KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
00374             Context->WaitEvent = &Event;
00375             ExReleaseFastMutex(&Ccb->DataListLock);
00376             KeWaitForSingleObject(&Event,
00377                 Executive,
00378                 KernelMode,
00379                 FALSE,
00380                 NULL);
00381             ExAcquireFastMutex(&Ccb->DataListLock);
00382         }
00383         Irp->IoStatus.Information = 0;
00384     }
00385     else
00386     {
00387         KIRQL oldIrql;
00388         if (IsListEmpty(&Ccb->ReadRequestListHead) ||
00389             Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
00390         {
00391             /* this is a new request */
00392             Irp->IoStatus.Information = 0;
00393             Context->WaitEvent = &Ccb->ReadEvent;
00394             InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
00395             if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
00396             {
00397                 /* there was already a request on the list */
00398                 IoAcquireCancelSpinLock(&oldIrql);
00399                 if (Irp->Cancel)
00400                 {
00401                     IoReleaseCancelSpinLock(oldIrql);
00402                     RemoveEntryList(&Context->ListEntry);
00403                     ExReleaseFastMutex(&Ccb->DataListLock);
00404                     Status = STATUS_CANCELLED;
00405                     goto done;
00406                 }
00407                 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
00408                 IoReleaseCancelSpinLock(oldIrql);
00409                 ExReleaseFastMutex(&Ccb->DataListLock);
00410                 IoMarkIrpPending(Irp);
00411                 Status = STATUS_PENDING;
00412                 goto done;
00413             }
00414         }
00415     }
00416 
00417     while (1)
00418     {
00419         Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
00420         Information = Irp->IoStatus.Information;
00421         Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
00422         ASSERT (Information <= Length);
00423         Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
00424         Length -= Information;
00425         Status = STATUS_SUCCESS;
00426 
00427         while (1)
00428         {
00429             if (Ccb->ReadDataAvailable == 0)
00430             {
00431                 ULONG ConnectionSideReadMode;
00432 
00433                 if (Ccb->PipeEnd == FILE_PIPE_CLIENT_END) ConnectionSideReadMode=Ccb->Fcb->ClientReadMode;
00434                 else ConnectionSideReadMode = Ccb->Fcb->ServerReadMode;
00435 
00436                 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
00437                 {
00438                     KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
00439                 }
00440                 if (Information > 0 &&
00441                     (ConnectionSideReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
00442                     Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
00443                 {
00444                     break;
00445                 }
00446                 if (((Ccb->PipeState != FILE_PIPE_CONNECTED_STATE) || (!Ccb->OtherSide)) && (Ccb->ReadDataAvailable == 0))
00447                 {
00448                     DPRINT("PipeState: %x\n", Ccb->PipeState);
00449                     Status = STATUS_PIPE_BROKEN;
00450                     break;
00451                 }
00452                 ExReleaseFastMutex(&Ccb->DataListLock);
00453 
00454                 if (IoIsOperationSynchronous(Irp))
00455                 {
00456                     /* Wait for ReadEvent to become signaled */
00457 
00458                     DPRINT("Waiting for readable data (%wZ)\n", &Ccb->Fcb->PipeName);
00459                     Status = KeWaitForSingleObject(&Ccb->ReadEvent,
00460                         UserRequest,
00461                         Irp->RequestorMode,
00462                         (FileObject->Flags & FO_ALERTABLE_IO),
00463                         NULL);
00464                     DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
00465 
00466                     ExAcquireFastMutex(&Ccb->DataListLock);
00467 
00468                     if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC) || (Status == STATUS_ALERTED))
00469                     {
00470                         Status = STATUS_CANCELLED;
00471                         break;
00472                     }
00473                     if (!NT_SUCCESS(Status))
00474                     {
00475                         ASSERT(FALSE);
00476                     }
00477                 }
00478                 else
00479                 {
00480                     Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
00481 
00482                     Context->WaitEvent = &Ccb->ReadEvent;
00483                     Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
00484 
00485                     if (NT_SUCCESS(Status))
00486                     {
00487                         Status = STATUS_PENDING;
00488                         goto done;
00489                     }
00490                     ExAcquireFastMutex(&Ccb->DataListLock);
00491                     break;
00492                 }
00493             }
00494             ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
00495 
00496             /* If the pipe type and read mode are both byte stream */
00497             if (Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE)
00498             {
00499                 DPRINT("Byte stream mode: Ccb->Data %x\n", Ccb->Data);
00500                 /* Byte stream mode */
00501                 while (Length > 0 && Ccb->ReadDataAvailable > 0)
00502                 {
00503                     CopyLength = min(Ccb->ReadDataAvailable, Length);
00504                     if ((ULONG_PTR)Ccb->ReadPtr + CopyLength <= (ULONG_PTR)Ccb->Data + Ccb->MaxDataLength)
00505                     {
00506                         memcpy(Buffer, Ccb->ReadPtr, CopyLength);
00507                         Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
00508                         if (Ccb->ReadPtr == (PVOID)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength))
00509                         {
00510                             Ccb->ReadPtr = Ccb->Data;
00511                         }
00512                     }
00513                     else
00514                     {
00515                         TempLength = (ULONG)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength - (ULONG_PTR)Ccb->ReadPtr);
00516                         memcpy(Buffer, Ccb->ReadPtr, TempLength);
00517                         memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Ccb->Data, CopyLength - TempLength);
00518                         Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->Data + CopyLength - TempLength);
00519                     }
00520 
00521                     Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
00522                     Length -= CopyLength;
00523                     Information += CopyLength;
00524 
00525                     Ccb->ReadDataAvailable -= CopyLength;
00526                     Ccb->WriteQuotaAvailable += CopyLength;
00527                 }
00528 
00529                 if ((Length == 0) || (Ccb->ReadDataAvailable == 0))
00530                 {
00531                     if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
00532                     {
00533                         KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
00534                     }
00535                     KeResetEvent(&Ccb->ReadEvent);
00536                     break;
00537                 }
00538             }
00539             else if (Ccb->Fcb->PipeType == FILE_PIPE_MESSAGE_TYPE)
00540             {
00541                 DPRINT("Message mode: Ccb>Data %x\n", Ccb->Data);
00542 
00543                 /* Check if buffer is full and the read pointer is not at the start of the buffer */
00544                 if ((Ccb->WriteQuotaAvailable == 0) && (Ccb->ReadPtr > Ccb->Data))
00545                 {
00546                     Ccb->WriteQuotaAvailable += (ULONG_PTR)Ccb->ReadPtr - (ULONG_PTR)Ccb->Data;
00547                     memcpy(Ccb->Data, Ccb->ReadPtr, (ULONG_PTR)Ccb->WritePtr - (ULONG_PTR)Ccb->ReadPtr);
00548                     Ccb->WritePtr = (PVOID)((ULONG_PTR)Ccb->WritePtr - ((ULONG_PTR)Ccb->ReadPtr - (ULONG_PTR)Ccb->Data));
00549                     Ccb->ReadPtr = Ccb->Data;
00550                     ASSERT((ULONG_PTR)Ccb->WritePtr < ((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength));
00551                     ASSERT(Ccb->WritePtr >= Ccb->Data);
00552                 }
00553 
00554                 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
00555                 if (Ccb->ReadDataAvailable)
00556                 {
00557                     ULONG NextMessageLength = 0;
00558 
00559                     /*First get the size of the message */
00560                     memcpy(&NextMessageLength, Ccb->ReadPtr, sizeof(NextMessageLength));
00561 
00562                     if ((NextMessageLength == 0) || (NextMessageLength > Ccb->ReadDataAvailable))
00563                     {
00564                         DPRINT1("Possible memory corruption.\n");
00565                         HexDump(Ccb->Data, (ULONG_PTR)Ccb->WritePtr - (ULONG_PTR)Ccb->Data);
00566                         ASSERT(FALSE);
00567                     }
00568 
00569                     /* Use the smaller value */
00570                     CopyLength = min(NextMessageLength, Length);
00571                     ASSERT(CopyLength > 0);
00572                     ASSERT(CopyLength <= Ccb->ReadDataAvailable);
00573                     /* retrieve the message from the buffer */
00574                     memcpy(Buffer, (PVOID)((ULONG_PTR)Ccb->ReadPtr + sizeof(NextMessageLength)), CopyLength);
00575 
00576                     if (Ccb->ReadDataAvailable > CopyLength)
00577                     {
00578                         if (CopyLength < NextMessageLength)
00579                         /* Client only requested part of the message */
00580                         {
00581                             /* Calculate the remaining message new size */
00582                             ULONG NewMessageSize = NextMessageLength-CopyLength;
00583 
00584                             /* Update ReadPtr to point to new Message size location */
00585                             Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
00586 
00587                             /* Write a new Message size to buffer for the part of the message still there */
00588                             memcpy(Ccb->ReadPtr, &NewMessageSize, sizeof(NewMessageSize));
00589                         }
00590                         else
00591                         /* Client wanted the entire message */
00592                         {
00593                             /* Update ReadPtr to point to next message size */
00594                             Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength + sizeof(CopyLength));
00595                         }
00596                     }
00597                     else
00598                     {
00599                         /* This was the last Message, so just zero start of buffer for safety sake */
00600                         memset(Ccb->Data, 0, NextMessageLength + sizeof(NextMessageLength));
00601 
00602                         /* Reset to MaxDataLength as partial message retrievals dont
00603                            give the length back to Quota */
00604                         Ccb->WriteQuotaAvailable = Ccb->MaxDataLength;
00605 
00606                         /* reset read and write pointer to beginning of buffer */
00607                         Ccb->WritePtr = Ccb->Data;
00608                         Ccb->ReadPtr = Ccb->Data;
00609                     }
00610 #ifndef NDEBUG
00611                     DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
00612                     HexDump((PUCHAR)Buffer, CopyLength);
00613 #endif
00614 
00615                     Information += CopyLength;
00616 
00617                     Ccb->ReadDataAvailable -= CopyLength;
00618 
00619                     if ((ULONG)Ccb->WriteQuotaAvailable > (ULONG)Ccb->MaxDataLength) ASSERT(FALSE);
00620                 }
00621 
00622                 if (Information > 0)
00623                 {
00624                     ULONG ConnectionSideReadMode;
00625 
00626                     if (Ccb->PipeEnd == FILE_PIPE_CLIENT_END) ConnectionSideReadMode=Ccb->Fcb->ClientReadMode;
00627                     else ConnectionSideReadMode = Ccb->Fcb->ServerReadMode;
00628 
00629                     if ((ConnectionSideReadMode == FILE_PIPE_BYTE_STREAM_MODE) && (Ccb->ReadDataAvailable) && (Length > CopyLength))
00630                     {
00631                         Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
00632                         Length -= CopyLength;
00633                     }
00634                     else
00635                     {
00636                         KeResetEvent(&Ccb->ReadEvent);
00637 
00638                         if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->WriteQuotaAvailable > 0) && (Ccb->OtherSide))
00639                         {
00640                             KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
00641                         }
00642                         break;
00643                     }
00644                 }
00645             }
00646             else
00647             {
00648                 DPRINT1("Unhandled Pipe Mode!\n");
00649                 ASSERT(FALSE);
00650             }
00651         }
00652         Irp->IoStatus.Information = Information;
00653         Irp->IoStatus.Status = Status;
00654 
00655         ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
00656 
00657         if (IoIsOperationSynchronous(Irp))
00658         {
00659             RemoveEntryList(&Context->ListEntry);
00660             if (!IsListEmpty(&Ccb->ReadRequestListHead))
00661             {
00662                 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
00663                 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
00664             }
00665             ExReleaseFastMutex(&Ccb->DataListLock);
00666             IoCompleteRequest(Irp, IO_NO_INCREMENT);
00667 
00668             DPRINT("NpfsRead done (Status %lx)\n", Status);
00669             return Status;
00670         }
00671         else
00672         {
00673             KIRQL oldIrql;
00674 
00675             if (IsOriginalRequest)
00676             {
00677                 IsOriginalRequest = FALSE;
00678                 OriginalStatus = Status;
00679             }
00680             if (Status == STATUS_PENDING)
00681             {
00682                 ExReleaseFastMutex(&Ccb->DataListLock);
00683                 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
00684                 return OriginalStatus;
00685             }
00686             RemoveEntryList(&Context->ListEntry);
00687             IoCompleteRequest(Irp, IO_NO_INCREMENT);
00688             if (IsListEmpty(&Ccb->ReadRequestListHead))
00689             {
00690                 ExReleaseFastMutex(&Ccb->DataListLock);
00691                 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
00692                 return OriginalStatus;
00693             }
00694 
00695             IoAcquireCancelSpinLock(&oldIrql);
00696             Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
00697 
00698             Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
00699             /* Verify the Irp wasnt cancelled */
00700             if (Irp->Cancel)
00701             {
00702                 IoReleaseCancelSpinLock(oldIrql);
00703                 RemoveEntryList(&Context->ListEntry);
00704                 ExReleaseFastMutex(&Ccb->DataListLock);
00705                 Status = STATUS_CANCELLED;
00706                 goto done;
00707             }
00708             /* The Irp will now be handled, so remove the CancelRoutine */
00709             (void)IoSetCancelRoutine(Irp, NULL);
00710             IoReleaseCancelSpinLock(oldIrql);
00711         }
00712     }
00713 
00714 done:
00715     Irp->IoStatus.Status = Status;
00716 
00717     if (Status != STATUS_PENDING)
00718     {
00719         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00720     }
00721     DPRINT("NpfsRead done (Status %lx)\n", Status);
00722 
00723     return Status;
00724 }
00725 
00726 NTSTATUS NTAPI
00727 NpfsWrite(PDEVICE_OBJECT DeviceObject,
00728           PIRP Irp)
00729 {
00730     PIO_STACK_LOCATION IoStack;
00731     PFILE_OBJECT FileObject;
00732     PNPFS_FCB Fcb = NULL;
00733     PNPFS_CCB Ccb = NULL;
00734     PNPFS_CCB ReaderCcb;
00735     PUCHAR Buffer;
00736     NTSTATUS Status = STATUS_SUCCESS;
00737     ULONG Length;
00738     ULONG Offset;
00739     ULONG Information = 0;
00740     ULONG CopyLength;
00741     ULONG TempLength;
00742 
00743     DPRINT("NpfsWrite()\n");
00744 
00745     IoStack = IoGetCurrentIrpStackLocation(Irp);
00746     FileObject = IoStack->FileObject;
00747     DPRINT("FileObject %p\n", FileObject);
00748     DPRINT("Pipe name %wZ\n", &FileObject->FileName);
00749 
00750     Ccb = FileObject->FsContext2;
00751 
00752     /* Fail, if the CCB is not a pipe CCB */
00753     if (Ccb->Type != CCB_PIPE)
00754     {
00755         DPRINT("Not a pipe!\n");
00756         Status = STATUS_INVALID_PARAMETER;
00757         Length = 0;
00758         goto done;
00759     }
00760 
00761     ReaderCcb = Ccb->OtherSide;
00762     Fcb = Ccb->Fcb;
00763 
00764     Length = IoStack->Parameters.Write.Length;
00765     Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
00766 
00767     if (Irp->MdlAddress == NULL)
00768     {
00769         DPRINT("Irp->MdlAddress == NULL\n");
00770         Status = STATUS_UNSUCCESSFUL;
00771         Length = 0;
00772         goto done;
00773     }
00774 
00775     if ((ReaderCcb == NULL) || (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
00776     {
00777         DPRINT("Pipe is NOT connected!\n");
00778         if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
00779             Status = STATUS_PIPE_LISTENING;
00780         else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
00781             Status = STATUS_PIPE_DISCONNECTED;
00782         else
00783             Status = STATUS_UNSUCCESSFUL;
00784         Length = 0;
00785         goto done;
00786     }
00787 
00788     if (ReaderCcb->Data == NULL)
00789     {
00790         DPRINT("Pipe is NOT writable!\n");
00791         Status = STATUS_UNSUCCESSFUL;
00792         Length = 0;
00793         goto done;
00794     }
00795 
00796     Status = STATUS_SUCCESS;
00797     Buffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
00798 
00799     if (!Buffer)
00800     {
00801         DPRINT("MmGetSystemAddressForMdlSafe failed\n");
00802         Status = STATUS_INSUFFICIENT_RESOURCES;
00803         Length = 0;
00804         goto done;
00805 
00806     }
00807 
00808     ExAcquireFastMutex(&ReaderCcb->DataListLock);
00809 
00810     DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
00811 
00812 #ifndef NDEBUG
00813     HexDump(Buffer, Length);
00814 #endif
00815 
00816     while(1)
00817     {
00818         if ((ReaderCcb->WriteQuotaAvailable == 0))
00819         {
00820             if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE || !Ccb->OtherSide)
00821             {
00822                 Status = STATUS_PIPE_BROKEN;
00823                 ExReleaseFastMutex(&ReaderCcb->DataListLock);
00824                 goto done;
00825             }
00826             KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
00827             ExReleaseFastMutex(&ReaderCcb->DataListLock);
00828 
00829             DPRINT("Write Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
00830             Status = KeWaitForSingleObject(&Ccb->WriteEvent,
00831                 UserRequest,
00832                 Irp->RequestorMode,
00833                 (FileObject->Flags & FO_ALERTABLE_IO),
00834                 NULL);
00835             DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status);
00836 
00837             if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC) || (Status == STATUS_ALERTED))
00838             {
00839                 Status = STATUS_CANCELLED;
00840                 goto done;
00841             }
00842             if (!NT_SUCCESS(Status))
00843             {
00844                 ASSERT(FALSE);
00845             }
00846             /*
00847             * It's possible that the event was signaled because the
00848             * other side of pipe was closed.
00849             */
00850             if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE || !Ccb->OtherSide)
00851             {
00852                 DPRINT("PipeState: %x\n", Ccb->PipeState);
00853                 Status = STATUS_PIPE_BROKEN;
00854                 goto done;
00855             }
00856             /* Check that the pipe has not been closed */
00857             if (ReaderCcb->PipeState != FILE_PIPE_CONNECTED_STATE || !ReaderCcb->OtherSide)
00858             {
00859                 Status = STATUS_PIPE_BROKEN;
00860                 goto done;
00861             }
00862             ExAcquireFastMutex(&ReaderCcb->DataListLock);
00863         }
00864 
00865         if (Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE)
00866         {
00867             DPRINT("Byte stream mode: Ccb->Data %x, Ccb->WritePtr %x\n", ReaderCcb->Data, ReaderCcb->WritePtr);
00868 
00869             while (Length > 0 && ReaderCcb->WriteQuotaAvailable > 0)
00870             {
00871                 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
00872 
00873                 if ((ULONG_PTR)ReaderCcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
00874                 {
00875                     memcpy(ReaderCcb->WritePtr, Buffer, CopyLength);
00876                     ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + CopyLength);
00877                     if ((ULONG_PTR)ReaderCcb->WritePtr == (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
00878                     {
00879                         ReaderCcb->WritePtr = ReaderCcb->Data;
00880                     }
00881                 }
00882                 else
00883                 {
00884 
00885                     TempLength = (ULONG)((ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength -
00886                             (ULONG_PTR)ReaderCcb->WritePtr);
00887 
00888                     memcpy(ReaderCcb->WritePtr, Buffer, TempLength);
00889                     memcpy(ReaderCcb->Data, Buffer + TempLength, CopyLength - TempLength);
00890                     ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->Data + CopyLength - TempLength);
00891                 }
00892 
00893                 Buffer += CopyLength;
00894                 Length -= CopyLength;
00895                 Information += CopyLength;
00896 
00897                 ReaderCcb->ReadDataAvailable += CopyLength;
00898                 ReaderCcb->WriteQuotaAvailable -= CopyLength;
00899             }
00900 
00901             if (Length == 0)
00902             {
00903                 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
00904                 KeResetEvent(&Ccb->WriteEvent);
00905                 break;
00906             }
00907         }
00908         else if (Ccb->Fcb->PipeType == FILE_PIPE_MESSAGE_TYPE)
00909         {
00910             /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
00911             DPRINT("Message mode: Ccb->Data %x, Ccb->WritePtr %x\n",ReaderCcb->Data, ReaderCcb->WritePtr);
00912             if (Length > 0)
00913             {
00914                 /* Verify the WritePtr is still inside the buffer */
00915                 if (((ULONG_PTR)ReaderCcb->WritePtr > ((ULONG_PTR)ReaderCcb->Data + (ULONG_PTR)ReaderCcb->MaxDataLength)) ||
00916                 ((ULONG_PTR)ReaderCcb->WritePtr < (ULONG_PTR)ReaderCcb->Data))
00917                 {
00918                     DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
00919                     DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength %lu\n",
00920                         ReaderCcb->WritePtr, ReaderCcb->Data, ReaderCcb->MaxDataLength);
00921                     ASSERT(FALSE);
00922                 }
00923 
00924                 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable - sizeof(ULONG));
00925                 if (CopyLength > ReaderCcb->WriteQuotaAvailable)
00926                 {
00927                     DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
00928                         CopyLength, ReaderCcb->WriteQuotaAvailable);
00929                     ASSERT(FALSE);
00930                 }
00931 
00932                 /* First Copy the Length of the message into the pipes buffer */
00933                 memcpy(ReaderCcb->WritePtr, &CopyLength, sizeof(CopyLength));
00934 
00935                 /* Now the user buffer itself */
00936                 memcpy((PVOID)((ULONG_PTR)ReaderCcb->WritePtr + sizeof(CopyLength)), Buffer, CopyLength);
00937 
00938                 /* Update the write pointer */
00939                 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + sizeof(CopyLength) + CopyLength);
00940 
00941                 Information += CopyLength;
00942 
00943                 ReaderCcb->ReadDataAvailable += CopyLength;
00944 
00945                 ReaderCcb->WriteQuotaAvailable -= (CopyLength + sizeof(ULONG));
00946 
00947                 if ((ULONG_PTR)ReaderCcb->WriteQuotaAvailable > (ULONG)ReaderCcb->MaxDataLength)
00948                 {
00949                     DPRINT1("QuotaAvailable is greater than buffer size!\n");
00950                     ASSERT(FALSE);
00951                 }
00952             }
00953 
00954             if (Information > 0)
00955             {
00956                 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
00957                 KeResetEvent(&Ccb->WriteEvent);
00958                 break;
00959             }
00960         }
00961         else
00962         {
00963             DPRINT1("Unhandled Pipe Type Mode and Read Write Mode!\n");
00964             ASSERT(FALSE);
00965         }
00966     }
00967 
00968     ExReleaseFastMutex(&ReaderCcb->DataListLock);
00969 
00970 done:
00971     Irp->IoStatus.Status = Status;
00972     Irp->IoStatus.Information = Information;
00973 
00974     IoCompleteRequest(Irp, IO_NO_INCREMENT);
00975 
00976     DPRINT("NpfsWrite done (Status %lx)\n", Status);
00977 
00978     return Status;
00979 }
00980 
00981 /* EOF */

Generated on Sun May 27 2012 04:24:27 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.