Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrw.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
1.7.6.1
|