VOID HotKeyKrnlUnload( IN PDRIVER_OBJECT DriverObject ) { PDEVICE_OBJECT DeviceObject; LARGE_INTEGER lDelay; KdPrint(("[shadow] Enter HotKeyKrnlUnload...\n")); KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); // Delete device we have created DeviceObject = DriverObject->DeviceObject; while (DeviceObject) { if (((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDeviceObject) HotKeyKrnlDetach(DeviceObject); else IoDeleteDevice(DeviceObject); DeviceObject = DeviceObject->NextDevice; } if (gKeyCount > 0 && PendingIrp) { if (!CancelKeyboardIrp(PendingIrp)) KdPrint(("[shadow] Cancel irp failed\n")); } lDelay = RtlConvertLongToLargeInteger(100 * DELAY_ONE_MILLISECOND); while (gKeyCount) { KeDelayExecutionThread(KernelMode, FALSE, &lDelay); } KdPrint(("[shadow] Exit HotKeyKrnlUnload...\n")); }
NTSTATUS HelloDDKQueryInfomation(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKQueryInfomation\n")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; FILE_INFORMATION_CLASS info = stack->Parameters.QueryFile.FileInformationClass; if (info==FileStandardInformation ) { KdPrint(("FileStandardInformation\n")); PFILE_STANDARD_INFORMATION file_info = (PFILE_STANDARD_INFORMATION)pIrp->AssociatedIrp.SystemBuffer; file_info->EndOfFile = RtlConvertLongToLargeInteger(pDevExt->file_length); } NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = stack->Parameters.QueryFile.Length; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKQueryInfomation\n")); return status; }
/**************************************************************************** REMARKS: Function to register a driver heart beat callback function. The first function that is called sets the interval for all the callback functions and they will be called in the order they were registered. This function will implement this mechanism in whatever way is appropriate for the device driver environment. Note that currently there is no mechanism to specify the timer intervals at run-time, so we use a pre-determined value of 32 milliseconds that will be useful for NT display driver polling and DPVL update functions. ****************************************************************************/ void PMAPI PM_registerHeartBeatCallback( PM_heartBeat_cb cb, void *data) { // Kernel objects must always be resident in memory if (_PM_hb == NULL) { _PM_hb = ExAllocatePool(NonPagedPool, sizeof(_PM_heartBeat_t)); if (_PM_hb == NULL) return; RtlZeroMemory(_PM_hb, sizeof(_PM_heartBeat_t)); } // If first time called, start periodic timer (pre-determined intervals) if (_PM_hb->numHeartBeatCallbacks == 0) { KeInitializeTimer(&_PM_hb->kTimer); KeInitializeDpc(&_PM_hb->kTimerDpc,_PM_heartBeatTimeout,(void*)_PM_hb); KeSetTimerEx(&_PM_hb->kTimer,RtlConvertLongToLargeInteger(-10000*HEART_BEAT_MS), HEART_BEAT_MS,&_PM_hb->kTimerDpc); KeInitializeEvent(&_PM_hb->kTimerEvent,NotificationEvent,FALSE); // Callbacks will be executed within driver helper thread, not DPC _PM_hb->bThreadRunning = true; PsCreateSystemThread(&_PM_hb->hDriverThread,THREAD_ALL_ACCESS,NULL, NULL,NULL,_PM_heartBeatThread,(void*)_PM_hb); } // Add heart beat callback to list PM_lockSNAPAccess(-1,true); if (_PM_hb->numHeartBeatCallbacks < MAX_HEART_BEAT_CALLBACKS) { _PM_hb->heartBeat[_PM_hb->numHeartBeatCallbacks] = cb; _PM_hb->heartBeatData[_PM_hb->numHeartBeatCallbacks] = data; _PM_hb->numHeartBeatCallbacks++; } PM_unlockSNAPAccess(-1); }
VOID SoundDelay( IN ULONG Milliseconds ) /*++ Routine Description : Stall the current thread for the given number of milliseconds AT LEAST Arguments : Milliseconds - number of milliseconds to delay Return Value : None --*/ { LARGE_INTEGER Delay; // // Can't call SoundDelay() from high irql // if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { return; } // // First a tiny delay to synch us up with the timer otherwise we // may wait up to 15ms less time than we expected! // Delay = RtlConvertLongToLargeInteger(-1); KeDelayExecutionThread(KernelMode, FALSE, // Not alertable &Delay); Delay = RtlConvertLongToLargeInteger((-(LONG)Milliseconds) * 10000); KeDelayExecutionThread(KernelMode, FALSE, // Not alertable &Delay); }
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("DriverB:Enter B HelloDDKRead\n")); NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING DeviceName; RtlInitUnicodeString( &DeviceName, L"\\Device\\MyDDKDeviceA" ); //初始化objectAttributes OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); HANDLE hDevice; IO_STATUS_BLOCK status_block; //异步打开设备 ntStatus = ZwCreateFile(&hDevice, FILE_READ_ATTRIBUTES,//没有设SYNCHRONIZE &objectAttributes, &status_block, NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ, FILE_OPEN_IF,0,NULL,0); LARGE_INTEGER offset = RtlConvertLongToLargeInteger(0); if (NT_SUCCESS(ntStatus)) { ntStatus = ZwReadFile(hDevice,NULL,NULL,NULL,&status_block,NULL,0,&offset,NULL); } if (ntStatus==STATUS_PENDING) { KdPrint(("DriverB:ZwReadFile return STATUS_PENDING!\n")); PFILE_OBJECT FileObject; ntStatus = ObReferenceObjectByHandle(hDevice, EVENT_MODIFY_STATE, *ExEventObjectType, KernelMode, (PVOID*) &FileObject, NULL); if (NT_SUCCESS(ntStatus)) { KdPrint(("DriverB:Waiting...")); KeWaitForSingleObject(&FileObject->Event,Executive,KernelMode,FALSE,NULL); KdPrint(("DriverB:Driver A Read IRP completed now!\n")); ObDereferenceObject(FileObject); } } ZwClose(hDevice); ntStatus = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = ntStatus; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("DriverB:Leave B HelloDDKRead\n")); return ntStatus; }
BOOLEAN Sleep(ULONG MillionSecond) { NTSTATUS st; LARGE_INTEGER DelayTime; DelayTime = RtlConvertLongToLargeInteger(-10000*MillionSecond); st=KeDelayExecutionThread( KernelMode, FALSE, &DelayTime ); return (NT_SUCCESS(st)); }
VOID SoundMixerChangedItem( IN OUT PMIXER_INFO MixerInfo, IN OUT PMIXER_DATA_ITEM MixerItem ) { ASSERTMSG("Invalid mixer info!", MixerInfo->Key == MIX_INFO_KEY); /* ** There are 2 tasks : ** ** 1. Increment the current 'logical' time ** ** 2. Move the item to the head of the list and set its current time ** ** 3. Notify all those waiting for notification */ RemoveEntryList(&MixerItem->Entry); MixerInfo->CurrentLogicalTime = RtlLargeIntegerAdd(MixerInfo->CurrentLogicalTime, RtlConvertLongToLargeInteger(1L)); MixerItem->LastSet = MixerInfo->CurrentLogicalTime; InsertHeadList(&MixerInfo->ChangedItems, &MixerItem->Entry); /* ** Complete all notification Irps. */ { KIRQL OldIrql; PIRP pIrp; while (TRUE) { pIrp = SoundRemoveFromCancellableQ(&MixerInfo->NotifyQueue); if (pIrp == NULL) { break; } SoundMixerNotify(pIrp, MixerInfo); } } }
VOID SoundInitDataItem( PMIXER_INFO MixerInfo, PMIXER_DATA_ITEM MixerDataItem, USHORT Message, USHORT Id ) { ASSERTMSG("Mixer info not initialized!", MixerInfo->Key == MIX_INFO_KEY); MixerDataItem->LastSet = RtlConvertLongToLargeInteger(0L); MixerDataItem->Message = Message; MixerDataItem->Id = Id; InsertTailList(&MixerInfo->ChangedItems, &MixerDataItem->Entry); }
NTSTATUS DriverRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { Debug("Enter DriverRead"); IoMarkIrpPending(pIrp); MyDeviceExtend* tDevExtend = (MyDeviceExtend*)pDevObj->DeviceExtension; ULONG tTime = 3000000; tDevExtend->TimeCount = RtlConvertLongToLargeInteger(-10*tTime); tDevExtend->CurIrp = pIrp; NTSTATUS tRetStatus; tRetStatus = KeSetTimer(&tDevExtend->Timer,tDevExtend->TimeCount,&tDevExtend->DPC); Debug("Leave DriverRead"); return STATUS_PENDING; }
NTSTATUS NTAPI Connect( __in PWSK_SOCKET WskSocket, __in PSOCKADDR RemoteAddress ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; if (g_SocketsState != INITIALIZED || !WskSocket || !RemoteAddress) return STATUS_INVALID_PARAMETER; Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { return Status; } Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH) WskSocket->Dispatch)->WskConnect( WskSocket, RemoteAddress, 0, Irp); if (Status == STATUS_PENDING) { LARGE_INTEGER nWaitTime; nWaitTime = RtlConvertLongToLargeInteger(-1 * 1000 * 1000 * 10); if ((Status = KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, &nWaitTime)) == STATUS_TIMEOUT) { IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); } } if (Status == STATUS_SUCCESS) { Status = Irp->IoStatus.Status; } IoFreeIrp(Irp); return Status; }
VOID KBFDriverUnload(IN PDRIVER_OBJECT aDriverObject) { PAGED_CODE(); PDEVICE_OBJECT deviceObject = NULL; PDEVICE_OBJECT oldDeviceObject = NULL; PDEVICE_EXTENSION deviceExtension = NULL; LARGE_INTEGER lDelay; PRKTHREAD currentThread = NULL; if (g_filterStart == TRUE) { // delay some time lDelay = RtlConvertLongToLargeInteger(100 * DELAY_ONE_MILLISECOND); currentThread = KeGetCurrentThread(); // 将当前线程设置为低实时模式,以便让它的运行尽量少影响其他程序 KeSetPriorityThread(currentThread, LOW_REALTIME_PRIORITY); UNREFERENCED_PARAMETER(aDriverObject); DbgPrint("wykbflt.sys : DriverEntry unloading .\n"); // 遍历所有设备并一律解除绑定 deviceObject = aDriverObject->DeviceObject; while (deviceObject) { KBFDetach(deviceObject); deviceObject = deviceObject->NextDevice; } ASSERT(NULL == aDriverObject->DeviceObject); while (gC2pKeyCount) { KeDelayExecutionThread(KernelMode, FALSE, &lDelay); } } DbgPrint("wykbflt.sys : DriverEntry unload ok .\n"); return ; }
static void set_timer(unsigned long delta) { if (delta == LKL_TIMER_INIT) return; if (delta == LKL_TIMER_SHUTDOWN) { /* should not deliver timer shutdown twice */ if(timer_done) { DbgPrint("*** LKL_TIMER_SHUTDOWN called when timer_done ***"); while(1) ; } /* deque the timer so it won't be put in signaled state */ KeCancelTimer(&timer); /* timers run on DPCs. This returns after all active * DPCs have executed, which means the timer is * certainly not running nor being schduled after this * point. */ KeFlushQueuedDpcs(); /* signal the timer interrupt we're done */ timer_done = 1; /* the memory barrier is needed because it may be * possible for the compiler/cpu to call * KeReleaseSemaphore before assigning * timer_done. That would make the timer_thread wake * from the wait-for-multiple-objs without noticing * out signalling */ KeMemoryBarrier(); KeReleaseSemaphore(&timer_killer_sem, 0, 1, 0); return; } KeSetTimer(&timer, RtlConvertLongToLargeInteger((unsigned long)(-(delta/100))), NULL); }
NTSTATUS SpxTimerInit( VOID ) /*++ Routine Description: Initialize the timer component for the appletalk stack. Arguments: Return Value: --*/ { #if !defined(_PNP_POWER) BOOLEAN TimerStarted; #endif !_PNP_POWER // Initialize the timer and its associated Dpc. timer will be kicked // off when we get the first card arrival notification from ipx KeInitializeTimer(&spxTimer); CTEInitLock(&spxTimerLock); KeInitializeDpc(&spxTimerDpc, spxTimerDpcRoutine, NULL); spxTimerTick = RtlConvertLongToLargeInteger(SPX_TIMER_TICK); #if !defined(_PNP_POWER) TimerStarted = KeSetTimer(&spxTimer, spxTimerTick, &spxTimerDpc); CTEAssert(!TimerStarted); #endif !_PNP_POWER return STATUS_SUCCESS; }
dStatus kdi_GetFloppyController ( /* INPUT PARAMETERS: */ KdiContextPtr kdi_context /* UPDATE PARAMETERS: */ /* OUTPUT PARAMETERS: */ ) /* COMMENTS: ***************************************************************** * * DEFINITIONS: *************************************************************/ { /* DATA: ********************************************************************/ dSDDWord controller_wait; NTSTATUS wait_status; /* CODE: ********************************************************************/ if (!kdi_context->own_floppy_event) { controller_wait = RtlLargeIntegerNegate( RtlConvertLongToLargeInteger( (LONG)(10 * 1000 * 15000) ) ); wait_status = STATUS_SUCCESS; kdi_CheckedDump( QIC117INFO, "Q117i: Waiting Controller Event\n", 0l); if (kdi_context->controller_data.floppyEnablerApiSupported) { wait_status = kdi_FloppyEnabler( kdi_context->controller_data.apiDeviceObject, IOCTL_AQUIRE_FDC, &controller_wait); } else { wait_status = KeWaitForSingleObject( kdi_context->controller_event, Executive, KernelMode, dFALSE, &controller_wait); } if (wait_status == STATUS_TIMEOUT) { kdi_CheckedDump( QIC117INFO, "Q117i: Timeout Controller Event\n", 0l); kdi_context->current_interrupt = dFALSE; kdi_context->own_floppy_event = dFALSE; return kdi_Error( ERR_KDI_CONTROLLER_BUSY, FCT_ID, ERR_SEQ_1 ); } else { kdi_context->current_interrupt = dTRUE; kdi_context->own_floppy_event = dTRUE; kdi_CheckedDump( QIC117INFO, "Q117i: Have Controller Event\n", 0l); return kdi_Error( ERR_KDI_CLAIMED_CONTROLLER, FCT_ID, ERR_SEQ_1 ); } } return DONT_PANIC; }
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("DriverB:Enter B HelloDDKRead\n")); NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING DeviceName; RtlInitUnicodeString( &DeviceName, L"\\Device\\MyDDKDeviceA" ); PDEVICE_OBJECT DeviceObject = NULL; PFILE_OBJECT FileObject = NULL; //得到设备对象指针 ntStatus = IoGetDeviceObjectPointer(&DeviceName,FILE_ALL_ACCESS,&FileObject,&DeviceObject); KdPrint(("DriverB:FileObject:%x\n",FileObject)); KdPrint(("DriverB:DeviceObject:%x\n",DeviceObject)); if (!NT_SUCCESS(ntStatus)) { KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus )); ntStatus = STATUS_UNSUCCESSFUL; // 完成IRP pIrp->IoStatus.Status = ntStatus; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("DriverB:Leave B HelloDDKRead\n")); return ntStatus; } KEVENT event; KeInitializeEvent(&event,NotificationEvent,FALSE); IO_STATUS_BLOCK status_block; LARGE_INTEGER offsert = RtlConvertLongToLargeInteger(0); //创建异步IRP PIRP pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, NULL,0, &offsert,&status_block); KdPrint(("pNewIrp->UserEvent :%x\n",pNewIrp->UserEvent)); //设置pNewIrp->UserEvent,这样在IRP完成后可以通知该事件 pNewIrp->UserEvent = &event; KdPrint(("DriverB:pNewIrp:%x\n",pNewIrp)); PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp); stack->FileObject = FileObject; NTSTATUS status = IoCallDriver(DeviceObject,pNewIrp); if (status == STATUS_PENDING) { status = KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, // Not alertable NULL); status = status_block.Status; } ZwClose(FileObject); //关闭设备句柄 ObDereferenceObject( FileObject ); ntStatus = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = ntStatus; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("DriverB:Leave B HelloDDKRead\n")); return ntStatus; }
LONG NTAPI Receive( __in PWSK_SOCKET WskSocket, __out PVOID Buffer, __in ULONG BufferSize, __in ULONG Flags, __in ULONG Timeout ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; WSK_BUF WskBuffer = { 0 }; LONG BytesReceived = SOCKET_ERROR; NTSTATUS Status = STATUS_UNSUCCESSFUL; struct task_struct *thread = current; PVOID waitObjects[2]; int wObjCount = 1; if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize) return SOCKET_ERROR; if ((int) BufferSize <= 0) { return SOCKET_ERROR; } Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer); if (!NT_SUCCESS(Status)) { return SOCKET_ERROR; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { FreeWskBuffer(&WskBuffer); return SOCKET_ERROR; } Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH) WskSocket->Dispatch)->WskReceive( WskSocket, &WskBuffer, Flags, Irp); if (Status == STATUS_PENDING) { LARGE_INTEGER nWaitTime; LARGE_INTEGER *pTime; if (Timeout <= 0 || Timeout == MAX_SCHEDULE_TIMEOUT) { pTime = 0; } else { nWaitTime = RtlConvertLongToLargeInteger(-1 * Timeout * 1000 * 10); pTime = &nWaitTime; } waitObjects[0] = (PVOID) &CompletionEvent; if (thread->has_sig_event) { waitObjects[1] = (PVOID) &thread->sig_event; wObjCount = 2; } Status = KeWaitForMultipleObjects(wObjCount, &waitObjects[0], WaitAny, Executive, KernelMode, FALSE, pTime, NULL); switch (Status) { case STATUS_WAIT_0: // waitObjects[0] CompletionEvent if (Irp->IoStatus.Status == STATUS_SUCCESS) { BytesReceived = (LONG) Irp->IoStatus.Information; } else { #ifdef _WIN32_LOGLINK DbgPrint("RECV(%s) wsk(0x%p) multiWait err(0x%x:%s)\n", thread->comm, WskSocket, Irp->IoStatus.Status, GetSockErrorString(Irp->IoStatus.Status)); #else WDRBD_INFO("RECV(%s) wsk(0x%p) multiWait err(0x%x:%s)\n", thread->comm, WskSocket, Irp->IoStatus.Status, GetSockErrorString(Irp->IoStatus.Status)); #endif if(Irp->IoStatus.Status) { BytesReceived = -ECONNRESET; } } break; case STATUS_WAIT_1: BytesReceived = -EINTR; break; case STATUS_TIMEOUT: BytesReceived = -EAGAIN; break; default: BytesReceived = SOCKET_ERROR; break; } } else { if (Status == STATUS_SUCCESS) { BytesReceived = (LONG) Irp->IoStatus.Information; #ifdef _WIN32_LOGLINK DbgPrint("(%s) Rx No pending and data(%d) is avail\n", current->comm, BytesReceived); #else WDRBD_INFO("(%s) Rx No pending and data(%d) is avail\n", current->comm, BytesReceived); #endif } else { #ifdef _WIN32_LOGLINK DbgPrint("WskReceive Error Status=0x%x\n", Status); // EVENT_LOG! #else WDRBD_TRACE("WskReceive Error Status=0x%x\n", Status); // EVENT_LOG! #endif } } if (BytesReceived == -EINTR || BytesReceived == -EAGAIN) { // cancel irp in wsk subsystem IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); if (Irp->IoStatus.Information > 0) { //WDRBD_INFO("rx canceled but rx data(%d) avaliable.\n", Irp->IoStatus.Information); BytesReceived = Irp->IoStatus.Information; } } IoFreeIrp(Irp); FreeWskBuffer(&WskBuffer); return BytesReceived; }
LONG NTAPI SendLocal( __in PWSK_SOCKET WskSocket, __in PVOID Buffer, __in ULONG BufferSize, __in ULONG Flags, __in ULONG Timeout ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; WSK_BUF WskBuffer = { 0 }; LONG BytesSent = SOCKET_ERROR; NTSTATUS Status = STATUS_UNSUCCESSFUL; if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || ((int) BufferSize <= 0)) return SOCKET_ERROR; Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer); if (!NT_SUCCESS(Status)) { return SOCKET_ERROR; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { FreeWskBuffer(&WskBuffer); return SOCKET_ERROR; } Flags |= WSK_FLAG_NODELAY; Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH) WskSocket->Dispatch)->WskSend( WskSocket, &WskBuffer, Flags, Irp); if (Status == STATUS_PENDING) { LARGE_INTEGER nWaitTime; LARGE_INTEGER *pTime; if (Timeout <= 0 || Timeout == MAX_SCHEDULE_TIMEOUT) { pTime = NULL; } else { nWaitTime = RtlConvertLongToLargeInteger(-1 * Timeout * 1000 * 10); pTime = &nWaitTime; } Status = KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, pTime); switch (Status) { case STATUS_TIMEOUT: IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); BytesSent = -EAGAIN; break; case STATUS_WAIT_0: if (NT_SUCCESS(Irp->IoStatus.Status)) { BytesSent = (LONG) Irp->IoStatus.Information; } else { #ifdef _WIN32_LOGLINK DbgPrint("(%s) sent error(%s)\n", current->comm, GetSockErrorString(Irp->IoStatus.Status)); #else WDRBD_WARN("(%s) sent error(%s)\n", current->comm, GetSockErrorString(Irp->IoStatus.Status)); #endif switch (Irp->IoStatus.Status) { case STATUS_IO_TIMEOUT: BytesSent = -EAGAIN; break; case STATUS_INVALID_DEVICE_STATE: BytesSent = -EAGAIN; break; default: BytesSent = -ECONNRESET; break; } } break; default: #ifdef _WIN32_LOGLINK DbgPrint("KeWaitForSingleObject failed. status 0x%x\n", Status); #else WDRBD_ERROR("KeWaitForSingleObject failed. status 0x%x\n", Status); #endif BytesSent = SOCKET_ERROR; } } else { if (Status == STATUS_SUCCESS) { BytesSent = (LONG) Irp->IoStatus.Information; #ifdef _WIN32_LOGLINK DbgPrint("(%s) WskSend No pending: but sent(%d)!\n", current->comm, BytesSent); #else WDRBD_WARN("(%s) WskSend No pending: but sent(%d)!\n", current->comm, BytesSent); #endif } else { #ifdef _WIN32_LOGLINK DbgPrint("(%s) WskSend error(0x%x)\n", current->comm, Status); #else WDRBD_WARN("(%s) WskSend error(0x%x)\n", current->comm, Status); #endif BytesSent = SOCKET_ERROR; } } IoFreeIrp(Irp); FreeWskBuffer(&WskBuffer); return BytesSent; }
LONG NTAPI Send( __in PWSK_SOCKET WskSocket, __in PVOID Buffer, __in ULONG BufferSize, __in ULONG Flags, __in ULONG Timeout, __in KEVENT *send_buf_kill_event, __in struct drbd_transport *transport, __in enum drbd_stream stream ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; WSK_BUF WskBuffer = { 0 }; LONG BytesSent = SOCKET_ERROR; // DRBC_CHECK_WSK: SOCKET_ERROR be mixed EINVAL? NTSTATUS Status = STATUS_UNSUCCESSFUL; if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || ((int) BufferSize <= 0)) return SOCKET_ERROR; Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer); if (!NT_SUCCESS(Status)) { return SOCKET_ERROR; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { FreeWskBuffer(&WskBuffer); return SOCKET_ERROR; } Flags |= WSK_FLAG_NODELAY; Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH) WskSocket->Dispatch)->WskSend( WskSocket, &WskBuffer, Flags, Irp); if (Status == STATUS_PENDING) { LARGE_INTEGER nWaitTime; LARGE_INTEGER *pTime; int retry_count = 0; retry: if (Timeout <= 0 || Timeout == MAX_SCHEDULE_TIMEOUT) { pTime = NULL; } else { nWaitTime = RtlConvertLongToLargeInteger(-1 * Timeout * 1000 * 10); pTime = &nWaitTime; } { struct task_struct *thread = current; PVOID waitObjects[2]; int wObjCount = 1; waitObjects[0] = (PVOID) &CompletionEvent; #ifndef _WIN32_SEND_BUFFING // in send-buffering, Netlink , call_usermodehelper are distinguished to SendLocal // KILL event is only used in send-buffering thread while send block. // WIN32_V9_REFACTO_:required to refactoring that input param, log message are simplized. #else #endif Status = KeWaitForMultipleObjects(wObjCount, &waitObjects[0], WaitAny, Executive, KernelMode, FALSE, pTime, NULL); switch (Status) { case STATUS_TIMEOUT: #ifdef _WIN32_SEND_BUFFING if (wObjCount == 1) { retry_count++; WDRBD_WARN("(%s) sent timeout=%d sz=%d retry_count=%d WskSocket=%p IRP=%p\n", current->comm, Timeout, BufferSize, retry_count,WskSocket, Irp); // required to refactroing about retrying method. goto retry; } #endif if (transport != NULL) { if (!drbd_stream_send_timed_out(transport, stream)) { goto retry; } } IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); BytesSent = -EAGAIN; break; case STATUS_WAIT_0: if (NT_SUCCESS(Irp->IoStatus.Status)) { BytesSent = (LONG)Irp->IoStatus.Information; } else { WDRBD_WARN("tx error(%s) wsk(0x%p)\n", GetSockErrorString(Irp->IoStatus.Status), WskSocket); switch (Irp->IoStatus.Status) { case STATUS_IO_TIMEOUT: BytesSent = -EAGAIN; break; case STATUS_INVALID_DEVICE_STATE: BytesSent = -EAGAIN; break; default: BytesSent = -ECONNRESET; break; } } break; //case STATUS_WAIT_1: // common: sender or send_bufferinf thread's kill signal // IoCancelIrp(Irp); // KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); // BytesSent = -EINTR; // break; default: WDRBD_ERROR("Wait failed. status 0x%x\n", Status); BytesSent = SOCKET_ERROR; } } } else { if (Status == STATUS_SUCCESS) { BytesSent = (LONG) Irp->IoStatus.Information; WDRBD_WARN("(%s) WskSend No pending: but sent(%d)!\n", current->comm, BytesSent); } else { WDRBD_WARN("(%s) WskSend error(0x%x)\n", current->comm, Status); BytesSent = SOCKET_ERROR; } } IoFreeIrp(Irp); FreeWskBuffer(&WskBuffer); return BytesSent; }
PWSK_SOCKET NTAPI Accept( __in PWSK_SOCKET WskSocket, __out_opt PSOCKADDR LocalAddress, __out_opt PSOCKADDR RemoteAddress, __out_opt NTSTATUS *RetStaus, __in int timeout ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; PWSK_SOCKET AcceptedSocket = NULL; struct task_struct *thread = current; PVOID waitObjects[2]; int wObjCount = 1; if (g_SocketsState != INITIALIZED || !WskSocket) { *RetStaus = SOCKET_ERROR; return NULL; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { *RetStaus = Status; return NULL; } Status = ((PWSK_PROVIDER_LISTEN_DISPATCH) WskSocket->Dispatch)->WskAccept( WskSocket, 0, NULL, NULL, LocalAddress, RemoteAddress, Irp); if (Status == STATUS_PENDING) { LARGE_INTEGER nWaitTime; LARGE_INTEGER *pTime; if (timeout <= 0 || timeout == MAX_SCHEDULE_TIMEOUT) { pTime = 0; } else { nWaitTime = RtlConvertLongToLargeInteger(-1 * timeout * 10000000); pTime = &nWaitTime; } waitObjects[0] = (PVOID) &CompletionEvent; if (thread->has_sig_event) { waitObjects[1] = (PVOID) &thread->sig_event; wObjCount = 2; } Status = KeWaitForMultipleObjects(wObjCount, &waitObjects[0], WaitAny, Executive, KernelMode, FALSE, pTime, NULL); switch (Status) { case STATUS_WAIT_0: break; case STATUS_WAIT_0 + 1: IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); *RetStaus = -EINTR; break; case STATUS_TIMEOUT: IoCancelIrp(Irp); KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); *RetStaus = STATUS_TIMEOUT; break; default: WDRBD_ERROR("Unexpected Error Status=0x%x\n", Status); break; } } else { if (Status != STATUS_SUCCESS) { WDRBD_TRACE("Accept Error Status=0x%x\n", Status); } } AcceptedSocket = (Status == STATUS_SUCCESS) ? (PWSK_SOCKET) Irp->IoStatus.Information : NULL; IoFreeIrp(Irp); return AcceptedSocket; }
void initialize (void) { ULONG SidWithZeroSubAuthorities; ULONG SidWithOneSubAuthority; ULONG SidWithThreeSubAuthorities; ULONG SidWithFourSubAuthorities; SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; // // The following SID sizes need to be allocated // SidWithZeroSubAuthorities = GetSidLengthRequired( 0 ); SidWithOneSubAuthority = GetSidLengthRequired( 1 ); SidWithThreeSubAuthorities = GetSidLengthRequired( 3 ); SidWithFourSubAuthorities = GetSidLengthRequired( 4 ); // // Allocate and initialize the universal SIDs // NullSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); WorldSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); LocalSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); CreatorOwnerSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); InitializeSid( NullSid, &NullSidAuthority, 1 ); InitializeSid( WorldSid, &WorldSidAuthority, 1 ); InitializeSid( LocalSid, &LocalSidAuthority, 1 ); InitializeSid( CreatorOwnerSid, &CreatorSidAuthority, 1 ); *(GetSidSubAuthority( NullSid, 0 )) = SECURITY_NULL_RID; *(GetSidSubAuthority( WorldSid, 0 )) = SECURITY_WORLD_RID; *(GetSidSubAuthority( LocalSid, 0 )) = SECURITY_LOCAL_RID; *(GetSidSubAuthority( CreatorOwnerSid, 0 )) = SECURITY_CREATOR_OWNER_RID; // // Allocate and initialize the NT defined SIDs // NtAuthoritySid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithZeroSubAuthorities); DialupSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); NetworkSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); BatchSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); InteractiveSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); LocalSystemSid = (PSID)RtlAllocateHeap( RtlProcessHeap(), 0,SidWithOneSubAuthority); InitializeSid( NtAuthoritySid, &NtAuthority, 0 ); InitializeSid( DialupSid, &NtAuthority, 1 ); InitializeSid( NetworkSid, &NtAuthority, 1 ); InitializeSid( BatchSid, &NtAuthority, 1 ); InitializeSid( InteractiveSid, &NtAuthority, 1 ); InitializeSid( LocalSystemSid, &NtAuthority, 1 ); *(GetSidSubAuthority( DialupSid, 0 )) = SECURITY_DIALUP_RID; *(GetSidSubAuthority( NetworkSid, 0 )) = SECURITY_NETWORK_RID; *(GetSidSubAuthority( BatchSid, 0 )) = SECURITY_BATCH_RID; *(GetSidSubAuthority( InteractiveSid, 0 )) = SECURITY_INTERACTIVE_RID; *(GetSidSubAuthority( LocalSystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; // // Initialize the well known privilege values // SeCreateTokenPrivilege = RtlConvertLongToLargeInteger(SE_CREATE_TOKEN_PRIVILEGE); SeAssignPrimaryTokenPrivilege = RtlConvertLongToLargeInteger(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE); SeLockMemoryPrivilege = RtlConvertLongToLargeInteger(SE_LOCK_MEMORY_PRIVILEGE); SeIncreaseQuotaPrivilege = RtlConvertLongToLargeInteger(SE_INCREASE_QUOTA_PRIVILEGE); SeUnsolicitedInputPrivilege = RtlConvertLongToLargeInteger(SE_UNSOLICITED_INPUT_PRIVILEGE); SeTcbPrivilege = RtlConvertLongToLargeInteger(SE_TCB_PRIVILEGE); SeSecurityPrivilege = RtlConvertLongToLargeInteger(SE_SECURITY_PRIVILEGE); SeTakeOwnershipPrivilege = RtlConvertLongToLargeInteger(SE_TAKE_OWNERSHIP_PRIVILEGE); SeLoadDriverPrivilege = RtlConvertLongToLargeInteger(SE_LOAD_DRIVER_PRIVILEGE); SeCreatePagefilePrivilege = RtlConvertLongToLargeInteger(SE_CREATE_PAGEFILE_PRIVILEGE); SeIncreaseBasePriorityPrivilege = RtlConvertLongToLargeInteger(SE_INC_BASE_PRIORITY_PRIVILEGE); SeSystemProfilePrivilege = RtlConvertLongToLargeInteger(SE_SYSTEM_PROFILE_PRIVILEGE); SeSystemtimePrivilege = RtlConvertLongToLargeInteger(SE_SYSTEMTIME_PRIVILEGE); SeProfileSingleProcessPrivilege = RtlConvertLongToLargeInteger(SE_PROF_SINGLE_PROCESS_PRIVILEGE); SeCreatePermanentPrivilege = RtlConvertLongToLargeInteger(SE_CREATE_PERMANENT_PRIVILEGE); SeBackupPrivilege = RtlConvertLongToLargeInteger(SE_BACKUP_PRIVILEGE); SeRestorePrivilege = RtlConvertLongToLargeInteger(SE_RESTORE_PRIVILEGE); SeShutdownPrivilege = RtlConvertLongToLargeInteger(SE_SHUTDOWN_PRIVILEGE); SeDebugPrivilege = RtlConvertLongToLargeInteger(SE_DEBUG_PRIVILEGE); SeAuditPrivilege = RtlConvertLongToLargeInteger(SE_AUDIT_PRIVILEGE); SeSystemEnvironmentPrivilege = RtlConvertLongToLargeInteger(SE_SYSTEM_ENVIRONMENT_PRIVILEGE); SeChangeNotifyPrivilege = RtlConvertLongToLargeInteger(SE_CHANGE_NOTIFY_PRIVILEGE); SeRemoteShutdownPrivilege = RtlConvertLongToLargeInteger(SE_REMOTE_SHUTDOWN_PRIVILEGE); }
int WSPAPI WSPSendDisconnect ( SOCKET Handle, LPWSABUF lpOutboundDisconnectData, LPINT lpErrno ) /*++ Routine Description: This routine is used on connection-oriented sockets to disable transmission, and to initiate termination of the connection along with the transmission of disconnect data, if any. After this routine has been successfully issued, subsequent sends are disallowed. lpOutboundDisconnectData, if not NULL, points to a buffer containing the outgoing disconnect data to be sent to the remote party. Note that WSPSendDisconnect() does not close the socket, and resources attached to the socket will not be freed until WSPCloseSocket() is invoked. WSPSendDisconnect() does not block regardless of the SO_LINGER setting on the socket. A WinSock SPI client should not rely on being able to re-use a socket after it has been WSPSendDisconnect()ed. In particular, a WinSock provider is not required to support the use of WSPConnect() on such a socket. Arguments: s - A descriptor identifying a socket. lpOutboundDisconnectData - A pointer to the outgoing disconnect data. lpErrno - A pointer to the error code. Return Value: If no error occurs, WSPSendDisconnect() returns 0. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code is available in lpErrno. --*/ { NTSTATUS status; PWINSOCK_TLS_DATA tlsData; PSOCKET_INFORMATION socket; IO_STATUS_BLOCK ioStatusBlock; int err; AFD_PARTIAL_DISCONNECT_INFO disconnectInfo; WS_ENTER( "WSPSendDisconnect", (PVOID)Handle, (PVOID)lpOutboundDisconnectData, NULL, NULL ); WS_ASSERT( lpErrno != NULL ); err = SockEnterApi( &tlsData ); if( err != NO_ERROR ) { WS_EXIT( "WSPSendDisconnect", SOCKET_ERROR, TRUE ); *lpErrno = err; return SOCKET_ERROR; } // // Set up locals so that we know how to clean up on exit. // socket = NULL; // // Find a pointer to the socket structure corresponding to the // passed-in handle. // socket = SockFindAndReferenceSocket( Handle, TRUE ); if ( socket == NULL ) { err = WSAENOTSOCK; goto exit; } // // Acquire the lock that protect this socket. // SockAcquireSocketLockExclusive( socket ); // // If this is not a datagram socket, then it must be connected in order // for WSPSendDisconnect() to be a legal operation. // if ( !IS_DGRAM_SOCK(socket) && !SockIsSocketConnected( socket ) ) { err = WSAENOTCONN; goto exit; } #ifdef _AFD_SAN_SWITCH_ // // Handle SAN disconnect first // if (SockSanEnabled && socket->SanSocket && socket->SanSocket->IsConnected == CONNECTED) { socket->SendShutdown = TRUE; SockSanShutdown(socket, SD_SEND); goto exit; } #endif //_AFD_SAN_SWITCH_ // // Setup the disconnect info. // disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_SEND; disconnectInfo.Timeout = RtlConvertLongToLargeInteger( -1 ); // !!! temporary HACK for tp4! if( socket->AddressFamily == AF_OSI ) { disconnectInfo.DisconnectMode = AFD_ABORTIVE_DISCONNECT; } __try { if( lpOutboundDisconnectData != NULL && lpOutboundDisconnectData->buf != NULL && lpOutboundDisconnectData->len > 0 ) { INT bufferLength; // // Set the disconnect data on the socket. // bufferLength = (INT)lpOutboundDisconnectData->len; err = SockSetConnectData( socket, IOCTL_AFD_SET_DISCONNECT_DATA, (PCHAR)lpOutboundDisconnectData->buf, bufferLength, &bufferLength ); if( err != NO_ERROR ) { goto exit; } } } __except (SOCK_EXCEPTION_FILTER()) { err = WSAEFAULT; goto exit; } // // Note in the socket state that sends are shutdown. // socket->SendShutdown = TRUE; IF_DEBUG(SHUTDOWN) { WS_PRINT(( "starting WSPSendDisconnect for socket %lx\n", Handle )); } // // Send the IOCTL to AFD for processing. // status = NtDeviceIoControlFile( socket->HContext.Handle, tlsData->EventHandle, NULL, // APC Routine NULL, // APC Context &ioStatusBlock, IOCTL_AFD_PARTIAL_DISCONNECT, &disconnectInfo, sizeof(disconnectInfo), NULL, // OutputBuffer 0L // OutputBufferLength ); if ( status == STATUS_PENDING ) { SockReleaseSocketLock( socket ); SockWaitForSingleObject( tlsData->EventHandle, Handle, SOCK_NEVER_CALL_BLOCKING_HOOK, SOCK_NO_TIMEOUT ); SockAcquireSocketLockExclusive( socket ); status = ioStatusBlock.Status; } if ( !NT_SUCCESS(status) ) { err = SockNtStatusToSocketError( status ); goto exit; } // // Notify the helper DLL that the socket has been shut down. // err = SockNotifyHelperDll( socket, WSH_NOTIFY_SHUTDOWN_SEND ); if ( err != NO_ERROR ) { goto exit; } exit: IF_DEBUG(SHUTDOWN) { if ( err != NO_ERROR ) { WS_PRINT(( "WSPSendDisconnect() on socket %lx (%lx) failed: %ld.\n", Handle, socket, err )); } else { WS_PRINT(( "WSPSendDisconnect() on socket %lx (%lx) succeeded.\n", Handle, socket )); } } if ( socket != NULL ) { SockReleaseSocketLock( socket ); SockDereferenceSocket( socket ); } if ( err != NO_ERROR ) { WS_EXIT( "WSPSendDisconnect", SOCKET_ERROR, TRUE ); *lpErrno = err; return SOCKET_ERROR; } WS_EXIT( "WSPSendDisconnect", NO_ERROR, FALSE ); return NO_ERROR; } // WSPSendDisconnect
static _Check_return_ NTSTATUS LcFetchFileByChunks ( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ HANDLE SourceFileHandle, _In_ PLARGE_INTEGER SourceFileSize, _Out_ PLARGE_INTEGER BytesCopied ) /*++ Summary: This function copies the original file from the 'SourceFileHandle' to the currently opened file ('FltObjects->FileObject') by chunks. It maintains its own list of chunks, and extends it, if there are no chunks available to read into. Write operation goes from one chunk to another in a sequential order. If the next chunk is empty, write waits for the read to be completed, and proceeds. There are simple rules for chunks allocation: 1. Up to two chunks are initially allocated: a) If the file is smaller than the 'ChunkSize', only one chunk is allocated with buffer that is equal to the file size. b) If the file is larger than the 'ChunkSize', two chunks are allocated, taking the file size into account for the second chunk size. 2. If all chunks currently allocated are full and awaiting to be written to a disk, and the current amount of chunks is lesser than 'MaxChunks', an additional chunk is allocated. There is a corner case, when the actual file size differs from the reported one. In this case one of the chunks in the list will be smaller than the 'ChunkSize'. For example, 'MaxChunks' is 3, ChunkSize is '10', file size reported is '12', and actual file size is '25'. Two chunks will be initially allocated: [1] 10b; [2] (12-10)=2b. Later on, when all of them will be filled in with the data, and EOF will not be received, because the actual size is 25b, another chunk [3] of size 10b (ChunkSize) will be allocated. In total, there will be three chunks: 10b, 2b, and 10b. We don't reallocate the 2nd chunk, because this driver is supposed to be used with a proper filesystems, but making this modification might be a valuable TODO item. Let's look at how chunks work. All chunks are stored in the doubly-linked list. [Head] node doesn't contain any buffer to store data in. Refer to the 'FILE_CHUNK' structure for details. MSDN about lists: http://msdn.microsoft.com/en-us/library/windows/hardware/ff563802(v=vs.85).aspx For large files we will have two chunks from the beginning. [Head] <-> [1] <-> [2] <-> [Head] There are pointers for [R]ead and [W]rite. When the first chunk is being read, the list will look like the following: [Head] <-> [1] <-> [2] <-> [Head] [W] [R] [W] is awaiting for the [1] to be filled in with the data before writing it to the disk. When the [1] chunk is filled with the data: [Head] <-> [1*] <-> [2] <-> [Head] [W] [R] [1] is full and is being written to a disk, and we're reading into chunk [2]. Let's also assume that the reads are faster then writes. When the [2] chunk is full, there are no free chunks available: [Head] <-> [1*] <-> [2*] <-> [Head] [W] [R] If the current amount of chunks is lesser than the 'MaxChunks' value, a new chunk will be allocated before the next [R] node. In this case it will be added before [Head] to the end of the list, and read will continue: [Head] <-> [1*] <-> [2*] <-> [3] <-> [Head] [W] [R] Then [W] and [R] finish, and [W] moves to the [2] chunk. [Head] <-> [1] <-> [2*] <-> [3*] <-> [Head] [W] [R] [R] sees that [1] chunk is available, and reads into it: [Head] <-> [1] <-> [2*] <-> [3*] <-> [Head] [R] [W] After [R] finishes reading, there are no free chunks again: [Head] <-> [1*] <-> [2*] <-> [3*] <-> [Head] [R] [W] A new chunk can be allocated again before the [2]: [Head] <-> [1*] <-> [4] <-> [2*] <-> [3*] <-> [Head] [R] [W] With this approach, [R] will fill chunks [1]->[2]->[3]->[1]->[4], and write will write them in the same order. I.e. allocating a new chunk before the next filled chunk (if the amount of chunks is lesser than the 'MaxChunks') makes sure that the data is written sequentially, and there is no need to constantly seek in the file. Arguments: FltObjects - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing opaque handles to this filter, instance, its associated volume and file object. SourceFileHandle - Handle to the source file to copy content from. SourceFileSize - Size of the source file. BytesCopied - Pointer to the LARGE_INTEGER structure that receives the amount of bytes copied. Return Value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; LIST_ENTRY chunksListHead = { 0 }; ULONG chunkListLength = 0; // State of the R/W operations. BOOLEAN readComplete = FALSE; BOOLEAN writeComplete = FALSE; PFILE_CHUNK readChunk = NULL; PFILE_CHUNK writeChunk = NULL; BOOLEAN eof = FALSE; BOOLEAN waitingForRead = FALSE; KEVENT writeEvent = { 0 }; WRITE_CALLBACK_CONTEXT writeCallbackContext = { 0 }; LARGE_INTEGER waitTimeout = { 0 }; LARGE_INTEGER zeroTimeout = { 0 }; IO_STATUS_BLOCK statusBlock = { 0 }; LARGE_INTEGER remainingBytes = { 0 }; LARGE_INTEGER totalBytesRead = { 0 }; LARGE_INTEGER totalBytesWritten = { 0 }; LARGE_INTEGER sourceFileOffset = { 0 }; LARGE_INTEGER destinationFileOffset = { 0 }; PAGED_CODE(); FLT_ASSERT(FltObjects != NULL); FLT_ASSERT(SourceFileHandle != NULL); FLT_ASSERT(SourceFileSize != NULL); FLT_ASSERT(SourceFileSize->QuadPart > 0); FLT_ASSERT(BytesCopied != NULL); FLT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); *BytesCopied = RtlConvertLongToLargeInteger(0); __try { // Set the relative timeout (1 stands for 100 nanoseconds). waitTimeout = RtlConvertLongToLargeInteger(-10000); waitTimeout.QuadPart *= TimeoutMilliseconds; KeInitializeEvent(&writeEvent, NotificationEvent, TRUE); writeCallbackContext.Event = &writeEvent; remainingBytes.QuadPart = SourceFileSize->QuadPart; NT_IF_FAIL_LEAVE(LcInitializeChunksList(FltObjects->Instance, &chunksListHead, remainingBytes, &chunkListLength)); for (;;) { if (waitingForRead) { // Wait for the read operation to finish. NT_IF_FAIL_LEAVE(ZwWaitForSingleObject(SourceFileHandle, FALSE, &waitTimeout)); readComplete = TRUE; } else { readComplete = ZwWaitForSingleObject(SourceFileHandle, FALSE, &zeroTimeout) == STATUS_SUCCESS; } writeComplete = KeReadStateEvent(&writeEvent) != 0; if (!eof && readComplete) { // If it's not the first read, update status of the current chunk. if (readChunk != NULL) { status = statusBlock.Status; if (NT_SUCCESS(status) || status == STATUS_END_OF_FILE) { ULONG bytesRead = (ULONG)statusBlock.Information; readChunk->BytesInBuffer = bytesRead; remainingBytes.QuadPart -= bytesRead; totalBytesRead.QuadPart += bytesRead; sourceFileOffset.QuadPart += bytesRead; if (status == STATUS_END_OF_FILE || bytesRead < readChunk->BufferSize) { eof = TRUE; status = STATUS_SUCCESS; // Will not be used later in this case, only to have the proper data here. remainingBytes.QuadPart = 0; } } NT_IF_FAIL_LEAVE(status); } // Move to the next available chunk and schedule read. if (!eof) { // If the remote file system returned an invalid file size, when we started reading it, // this value might be negative. Set it to the default, so the newly allocated chunk // will have the maximum allowed size. if (remainingBytes.QuadPart <= 0) { remainingBytes.QuadPart = ChunkSize; } NT_IF_FAIL_LEAVE(LcGetNextAvailableChunk( FltObjects->Instance, &chunksListHead, &readChunk, &chunkListLength, TRUE, // Read operation. &remainingBytes, &writeEvent, &waitTimeout)); // Schedule read operation for the current chunk. status = ZwReadFile( SourceFileHandle, NULL, NULL, NULL, &statusBlock, readChunk->Buffer, readChunk->BufferSize, &sourceFileOffset, NULL); NT_IF_FALSE_LEAVE(status == STATUS_PENDING || status == STATUS_SUCCESS, status); } } if (writeComplete) { if (!waitingForRead) { // If it's not the first write, update status of the current chunk. if (writeChunk != NULL) { NT_IF_FAIL_LEAVE(writeCallbackContext.Status); writeChunk->BytesInBuffer = 0; totalBytesWritten.QuadPart += writeCallbackContext.BytesWritten; destinationFileOffset.QuadPart += writeCallbackContext.BytesWritten; } NT_IF_FAIL_LEAVE(LcGetNextAvailableChunk( FltObjects->Instance, &chunksListHead, &writeChunk, &chunkListLength, FALSE, // Write operation. NULL, NULL, NULL)); } waitingForRead = FALSE; // If we don't have any data in the current chunk, restart from the beginning of the loop. if (writeChunk->BytesInBuffer == 0) { if (eof) { // We're done! break; } else { // Since we're waiting for the read to complete for the current chunk, // don't change the chunk position on next iteration. waitingForRead = TRUE; continue; } } KeClearEvent(&writeEvent); NT_IF_FAIL_LEAVE(FltWriteFile( FltObjects->Instance, FltObjects->FileObject, &destinationFileOffset, writeChunk->BytesInBuffer, writeChunk->Buffer, FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET, NULL, (PFLT_COMPLETED_ASYNC_IO_CALLBACK)&LcWriteCallback, &writeCallbackContext)); } } *BytesCopied = totalBytesWritten; } __finally { LcClearChunksList(FltObjects->Instance, &chunksListHead); } return status; }
BOOLEAN TSeVariableInitialization() /*++ Routine Description: This function initializes the global variables used in security tests. Arguments: None. Return Value: TRUE if variables successfully initialized. FALSE if not successfully initialized. --*/ { ULONG SidWithZeroSubAuthorities; ULONG SidWithOneSubAuthority; ULONG SidWithThreeSubAuthorities; ULONG SidWithFourSubAuthorities; SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockAuthority = BEDROCK_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockAAuthority = BEDROCKA_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockBAuthority = BEDROCKB_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockCAuthority = BEDROCKC_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockDAuthority = BEDROCKD_AUTHORITY; SID_IDENTIFIER_AUTHORITY BedrockEAuthority = BEDROCKE_AUTHORITY; // // The following SID sizes need to be allocated // SidWithZeroSubAuthorities = RtlLengthRequiredSid( 0 ); SidWithOneSubAuthority = RtlLengthRequiredSid( 1 ); SidWithThreeSubAuthorities = RtlLengthRequiredSid( 3 ); SidWithFourSubAuthorities = RtlLengthRequiredSid( 4 ); // // Allocate and initialize the universal SIDs // NullSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); WorldSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); LocalSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); CreatorOwnerSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); CreatorGroupSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); RtlInitializeSid( NullSid, &NullSidAuthority, 1 ); RtlInitializeSid( WorldSid, &WorldSidAuthority, 1 ); RtlInitializeSid( LocalSid, &LocalSidAuthority, 1 ); RtlInitializeSid( CreatorOwnerSid, &CreatorSidAuthority, 1 ); RtlInitializeSid( CreatorGroupSid, &CreatorSidAuthority, 1 ); *(RtlSubAuthoritySid( NullSid, 0 )) = SECURITY_NULL_RID; *(RtlSubAuthoritySid( WorldSid, 0 )) = SECURITY_WORLD_RID; *(RtlSubAuthoritySid( LocalSid, 0 )) = SECURITY_LOCAL_RID; *(RtlSubAuthoritySid( CreatorOwnerSid, 0 )) = SECURITY_CREATOR_OWNER_RID; *(RtlSubAuthoritySid( CreatorGroupSid, 0 )) = SECURITY_CREATOR_GROUP_RID; // // Allocate and initialize the NT defined SIDs // NtAuthoritySid = (PSID)TstAllocatePool(PagedPool,SidWithZeroSubAuthorities); DialupSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); NetworkSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); BatchSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); InteractiveSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); LocalSystemSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); RtlInitializeSid( NtAuthoritySid, &NtAuthority, 0 ); RtlInitializeSid( DialupSid, &NtAuthority, 1 ); RtlInitializeSid( NetworkSid, &NtAuthority, 1 ); RtlInitializeSid( BatchSid, &NtAuthority, 1 ); RtlInitializeSid( InteractiveSid, &NtAuthority, 1 ); RtlInitializeSid( LocalSystemSid, &NtAuthority, 1 ); *(RtlSubAuthoritySid( DialupSid, 0 )) = SECURITY_DIALUP_RID; *(RtlSubAuthoritySid( NetworkSid, 0 )) = SECURITY_NETWORK_RID; *(RtlSubAuthoritySid( BatchSid, 0 )) = SECURITY_BATCH_RID; *(RtlSubAuthoritySid( InteractiveSid, 0 )) = SECURITY_INTERACTIVE_RID; *(RtlSubAuthoritySid( LocalSystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; // // Allocate and initialize the Bedrock SIDs // BedrockDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); BedrockADomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); BedrockBDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); BedrockCDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); BedrockDDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); BedrockEDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities); FredSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); WilmaSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); PebblesSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); DinoSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); BarneySid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); BettySid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); BambamSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); FlintstoneSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); RubbleSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); AdultSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); ChildSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); NeandertholSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities); RtlInitializeSid( BedrockDomainSid, &BedrockAuthority, 3 ); *(RtlSubAuthoritySid( BedrockDomainSid, 0)) = BEDROCK_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockDomainSid, 1)) = BEDROCK_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockDomainSid, 2)) = BEDROCK_SUBAUTHORITY_2; RtlInitializeSid( BedrockADomainSid, &BedrockAAuthority, 3 ); *(RtlSubAuthoritySid( BedrockADomainSid, 0)) = BEDROCKA_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockADomainSid, 1)) = BEDROCKA_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockADomainSid, 2)) = BEDROCKA_SUBAUTHORITY_2; RtlInitializeSid( BedrockBDomainSid, &BedrockBAuthority, 3 ); *(RtlSubAuthoritySid( BedrockBDomainSid, 0)) = BEDROCKB_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockBDomainSid, 1)) = BEDROCKB_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockBDomainSid, 2)) = BEDROCKB_SUBAUTHORITY_2; RtlInitializeSid( BedrockCDomainSid, &BedrockCAuthority, 3 ); *(RtlSubAuthoritySid( BedrockCDomainSid, 0)) = BEDROCKC_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockCDomainSid, 1)) = BEDROCKC_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockCDomainSid, 2)) = BEDROCKC_SUBAUTHORITY_2; RtlInitializeSid( BedrockDDomainSid, &BedrockDAuthority, 3 ); *(RtlSubAuthoritySid( BedrockDDomainSid, 0)) = BEDROCKD_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockDDomainSid, 1)) = BEDROCKD_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockDDomainSid, 2)) = BEDROCKD_SUBAUTHORITY_2; RtlInitializeSid( BedrockEDomainSid, &BedrockEAuthority, 3 ); *(RtlSubAuthoritySid( BedrockEDomainSid, 0)) = BEDROCKE_SUBAUTHORITY_0; *(RtlSubAuthoritySid( BedrockEDomainSid, 1)) = BEDROCKE_SUBAUTHORITY_1; *(RtlSubAuthoritySid( BedrockEDomainSid, 2)) = BEDROCKE_SUBAUTHORITY_2; RtlCopySid( SidWithFourSubAuthorities, FredSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( FredSid )) += 1; *(RtlSubAuthoritySid( FredSid, 3)) = FRED_RID; RtlCopySid( SidWithFourSubAuthorities, WilmaSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( WilmaSid )) += 1; *(RtlSubAuthoritySid( WilmaSid, 3)) = WILMA_RID; RtlCopySid( SidWithFourSubAuthorities, PebblesSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( PebblesSid )) += 1; *(RtlSubAuthoritySid( PebblesSid, 3)) = PEBBLES_RID; RtlCopySid( SidWithFourSubAuthorities, DinoSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( DinoSid )) += 1; *(RtlSubAuthoritySid( DinoSid, 3)) = DINO_RID; RtlCopySid( SidWithFourSubAuthorities, BarneySid, BedrockDomainSid); *(RtlSubAuthorityCountSid( BarneySid )) += 1; *(RtlSubAuthoritySid( BarneySid, 3)) = BARNEY_RID; RtlCopySid( SidWithFourSubAuthorities, BettySid, BedrockDomainSid); *(RtlSubAuthorityCountSid( BettySid )) += 1; *(RtlSubAuthoritySid( BettySid, 3)) = BETTY_RID; RtlCopySid( SidWithFourSubAuthorities, BambamSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( BambamSid )) += 1; *(RtlSubAuthoritySid( BambamSid, 3)) = BAMBAM_RID; RtlCopySid( SidWithFourSubAuthorities, FlintstoneSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( FlintstoneSid )) += 1; *(RtlSubAuthoritySid( FlintstoneSid, 3)) = FLINTSTONE_RID; RtlCopySid( SidWithFourSubAuthorities, RubbleSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( RubbleSid )) += 1; *(RtlSubAuthoritySid( RubbleSid, 3)) = RUBBLE_RID; RtlCopySid( SidWithFourSubAuthorities, AdultSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( AdultSid )) += 1; *(RtlSubAuthoritySid( AdultSid, 3)) = ADULT_RID; RtlCopySid( SidWithFourSubAuthorities, ChildSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( ChildSid )) += 1; *(RtlSubAuthoritySid( ChildSid, 3)) = CHILD_RID; RtlCopySid( SidWithFourSubAuthorities, NeandertholSid, BedrockDomainSid); *(RtlSubAuthorityCountSid( NeandertholSid )) += 1; *(RtlSubAuthoritySid( NeandertholSid, 3)) = NEANDERTHOL_RID; CreateTokenPrivilege = RtlConvertLongToLargeInteger(SE_CREATE_TOKEN_PRIVILEGE); AssignPrimaryTokenPrivilege = RtlConvertLongToLargeInteger(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE); LockMemoryPrivilege = RtlConvertLongToLargeInteger(SE_LOCK_MEMORY_PRIVILEGE); IncreaseQuotaPrivilege = RtlConvertLongToLargeInteger(SE_INCREASE_QUOTA_PRIVILEGE); UnsolicitedInputPrivilege = RtlConvertLongToLargeInteger(SE_UNSOLICITED_INPUT_PRIVILEGE); TcbPrivilege = RtlConvertLongToLargeInteger(SE_TCB_PRIVILEGE); SecurityPrivilege = RtlConvertLongToLargeInteger(SE_SECURITY_PRIVILEGE); TakeOwnershipPrivilege = RtlConvertLongToLargeInteger(SE_TAKE_OWNERSHIP_PRIVILEGE); LpcReplyBoostPrivilege = RtlConvertLongToLargeInteger(SE_LPC_REPLY_BOOST_PRIVILEGE); CreatePagefilePrivilege = RtlConvertLongToLargeInteger(SE_CREATE_PAGEFILE_PRIVILEGE); IncreaseBasePriorityPrivilege = RtlConvertLongToLargeInteger(SE_INC_BASE_PRIORITY_PRIVILEGE); SystemProfilePrivilege = RtlConvertLongToLargeInteger(SE_SYSTEM_PROFILE_PRIVILEGE); SystemtimePrivilege = RtlConvertLongToLargeInteger(SE_SYSTEMTIME_PRIVILEGE); ProfileSingleProcessPrivilege = RtlConvertLongToLargeInteger(SE_PROF_SINGLE_PROCESS_PRIVILEGE); CreatePermanentPrivilege = RtlConvertLongToLargeInteger(SE_CREATE_PERMANENT_PRIVILEGE); BackupPrivilege = RtlConvertLongToLargeInteger(SE_BACKUP_PRIVILEGE); RestorePrivilege = RtlConvertLongToLargeInteger(SE_RESTORE_PRIVILEGE); ShutdownPrivilege = RtlConvertLongToLargeInteger(SE_SHUTDOWN_PRIVILEGE); DebugPrivilege = RtlConvertLongToLargeInteger(SE_DEBUG_PRIVILEGE); return TRUE; }
NTSTATUS LcFetchRemoteFile ( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PUNICODE_STRING SourceFile, _In_ PUNICODE_STRING TargetFile, _In_ BOOLEAN UseCustomHandler, _Out_ PLARGE_INTEGER BytesCopied ) /*++ Summary: This function copies the remote file content to the current file object. In order for the remote file to be fetched, make sure that the network redirector device is used, i.e. the 'SourceFile' root points to the '\Device\Mup\<path>'. Arguments: FltObjects - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing opaque handles to this filter, instance, its associated volume and file object. SourceFile - Path to the file to fetch content from. TargetFile - Path to the file to store content to. UseCustomHandler - Whether the file should be fetched by the user-mode client. BytesCopied - The amount of bytes copied. Return Value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; HANDLE sourceFileHandle = NULL; IO_STATUS_BLOCK statusBlock = { 0 }; FILE_STANDARD_INFORMATION standardInfo = { 0 }; FILE_END_OF_FILE_INFORMATION eofInfo = { 0 }; PAGED_CODE(); IF_FALSE_RETURN_RESULT(FltObjects != NULL, STATUS_INVALID_PARAMETER_1); IF_FALSE_RETURN_RESULT(SourceFile != NULL, STATUS_INVALID_PARAMETER_2); IF_FALSE_RETURN_RESULT(TargetFile != NULL, STATUS_INVALID_PARAMETER_3); IF_FALSE_RETURN_RESULT(BytesCopied != NULL, STATUS_INVALID_PARAMETER_5); FLT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); *BytesCopied = RtlConvertLongToLargeInteger(0); __try { LOG((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[LazyCopy] Fetching content from: '%wZ' -> '%wZ'\n", SourceFile, TargetFile)); if (UseCustomHandler) { NT_IF_FAIL_LEAVE(LcFetchFileInUserMode(SourceFile, TargetFile, BytesCopied)); } else { // // Open the source file and make sure it's not empty. // NT_IF_FAIL_LEAVE(LcOpenFile(SourceFile, TargetFile, &sourceFileHandle)); NT_IF_FAIL_LEAVE(ZwQueryInformationFile(sourceFileHandle, &statusBlock, &standardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation)); if (standardInfo.EndOfFile.QuadPart == 0) { // No need to copy an empty file. __leave; } // Extend the target file, so all readers that wait for the content to be copied will get the actual file size information. // Remote file system may return incorrect information, but we are doing it only for the cases, when multiple threads // try to access the same file, while we are fetching it. eofInfo.EndOfFile.QuadPart = standardInfo.EndOfFile.QuadPart; NT_IF_FAIL_LEAVE(FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &eofInfo, sizeof(eofInfo), FileEndOfFileInformation)); // // Copy source file contents into the local (target) file. // NT_IF_FAIL_LEAVE(LcFetchFileByChunks( FltObjects, sourceFileHandle, &standardInfo.EndOfFile, BytesCopied)); } } __finally { if (sourceFileHandle != NULL) { ZwClose(sourceFileHandle); } } return status; }
VOID DrainTransmit( PDIGI_CONTROLLER_EXTENSION ControllerExt, PDIGI_DEVICE_EXTENSION DeviceExt, PIRP Irp ) /*++ Routine Description: We do the necessary checks to determine if the controller has transmitted all the data it has been given. The check basically is: if( CIN == COUT TIN == TOUT TBusy == 0 ) transmit buffer is empty. NOTE: Care should be taken when using this function, and at what dispatch level it is being called from. I don't do any synch'ing with the WriteQueue in the DeviceObject. So it is potentially possible that data could keep getting put on the controller while the function is waiting for it to drain. Arguments: ControllerExt - a pointer to this devices controllers extension. DeviceObject - a pointer to this devices object. Irp - Pointer to the current Irp request whose context this function is being called. This allows us to determine if the Irp has been cancelled. Return Value: --*/ { PFEP_CHANNEL_STRUCTURE ChInfo; PCOMMAND_STRUCT CommandQ; COMMAND_STRUCT CmdStruct; UCHAR TBusy; ULONG count; USHORT OrgTout, Tin, Tout; TIME DelayInterval; ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress + DeviceExt->ChannelInfo.Offset); EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Tin = READ_REGISTER_USHORT( &ChInfo->tin ); Tout = READ_REGISTER_USHORT( &ChInfo->tout ); TBusy = READ_REGISTER_UCHAR( &ChInfo->tbusy ); DisableWindow( ControllerExt ); OrgTout = Tout; // // Get the command queue info // CommandQ = ((PCOMMAND_STRUCT)(ControllerExt->VirtualAddress + FEP_CIN)); EnableWindow( ControllerExt, ControllerExt->Global.Window ); READ_REGISTER_BUFFER_UCHAR( (PUCHAR)CommandQ, (PUCHAR)&CmdStruct, sizeof(CmdStruct) ); DisableWindow( ControllerExt ); // // Delay for 10 milliseconds // #if rmm < 807 DelayInterval = RtlConvertLongToLargeInteger( -10 * 10000 ); #else DelayInterval.QuadPart = -10 * 10000; #endif count = 0; while( ((Tin != Tout) || (TBusy) || (CmdStruct.cmHead != CmdStruct.cmTail)) && !Irp->Cancel ) { ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); // not DPC, or KeDelay won't ever return KeDelayExecutionThread( KernelMode, FALSE, &DelayInterval ); EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Tin = READ_REGISTER_USHORT( &ChInfo->tin ); Tout = READ_REGISTER_USHORT( &ChInfo->tout ); TBusy = READ_REGISTER_UCHAR( &ChInfo->tbusy ); DisableWindow( ControllerExt ); EnableWindow( ControllerExt, ControllerExt->Global.Window ); READ_REGISTER_BUFFER_UCHAR( (PUCHAR)CommandQ, (PUCHAR)&CmdStruct, sizeof(CmdStruct) ); DisableWindow( ControllerExt ); if( Tout != OrgTout ) { count = 0; OrgTout = Tout; } if( count++ > 2500 ) { // // We have waited for 25 seconds and haven't seen the transmit // buffer change. Assume we are in a deadlock flow control state // and exit! // // // We go ahead and flush the transmit queue because a close // may be following soon, and we don't want it to have to // wait again. Basically, it had its chance to drain. // FlushTransmitBuffer( ControllerExt, DeviceExt ); break; } } } // end DrainTransmit
DualErr CPGPdiskInterface::UnmountPGPdisk(PGPUInt8 drive, PGPBoolean isThisEmergency) { DualErr derr; PGPBoolean removedPGPdisk, unmountedChildren; PGPdisk *pPGD; PGPUInt32 i = 0; removedPGPdisk = unmountedChildren = FALSE; pgpAssert(IsLegalDriveNumber(drive)); // Verify that the PGPdisk exists and is mounted. if (NULL==(int)(pPGD = mPGPdisks.FindPGPdisk(drive))) derr = DualErr(kPGDMinorError_PGPdiskNotMounted); // If this PGPdisk has other PGPdisks mounted on it, we must perform a // depth-first unmount of all those PGPdisks first. while (derr.IsntError()) { PGPdisk *pClient; if (!(pClient = Interface->mPGPdisks.EnumPGPdisks(i++))) break; if (!IsUNCPath(pClient->GetPath()) && (pClient->GetLocalHostDrive() == drive)) { i = 0; derr = UnmountPGPdisk(pClient->GetDrive(), isThisEmergency); if (isThisEmergency) derr = DualErr::NoError; unmountedChildren = derr.IsntError(); } } // Check if the PGPdisk has open files. if (derr.IsntError()) { // If we unmounted any children, we may have to wait a little while // for the system to flush its cache. Try about 10 times. if (unmountedChildren) { i = 0; while (pPGD->HasOpenFiles() && (i++ < kMaxCheckOpenFilesAttempts)) { LARGE_INTEGER ticks = RtlConvertLongToLargeInteger(-500 * 10000); KeDelayExecutionThread(KernelMode, FALSE, &ticks); } } if (pPGD->HasOpenFiles()) derr = DualErr(kPGDMinorError_FilesOpenOnDrive); if (isThisEmergency) derr = DualErr::NoError; } // Remove the object from the global list and attempt the unmount. if (derr.IsntError()) { mPGPdisks.RemovePGPdisk(pPGD); removedPGPdisk = TRUE; derr = pPGD->Unmount(isThisEmergency); } // Delete the PGPdisk object. if (derr.IsntError()) { delete pPGD; } // Cleanup if an error occurred; if (derr.IsError()) { if (removedPGPdisk && pPGD->Mounted()) mPGPdisks.AddPGPdisk(pPGD); } return derr; }
int WSPAPI WSPShutdown( IN SOCKET Handle, IN int HowTo, OUT LPINT lpErrno ) /*++ Routine Description: This routine is used on all types of sockets to disable reception, transmission, or both. If how is SD_RECEIVE, subsequent receives on the socket will be disallowed. This has no effect on the lower protocol layers. For TCP sockets, if there is still data queued on the socket waiting to be received, or data arrives subsequently, the connection is reset, since the data cannot be delivered to the user. For UDP sockets, incoming datagrams are accepted and queued. In no case will an ICMP error packet be generated. If how is SD_SEND, subsequent sends on the socket are disallowed. For TCP sockets, a FIN will be sent. Setting how to SD_BOTH disables both sends and receives as described above. Note that WSPShutdown() does not close the socket, and resources attached to the socket will not be freed until WSPCloseSocket() is invoked. WSPShutdown() does not block regardless of the SO_LINGER setting on the socket. A WinSock SPI client should not rely on being able to re-use a socket after it has been shut down. In particular, a WinSock service provider is not required to support the use of WSPConnect() on such a socket. Arguments: s - A descriptor identifying a socket. how - A flag that describes what types of operation will no longer be allowed. lpErrno - A pointer to the error code. Return Value: If no error occurs, WSPShutdown() returns 0. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code is available in lpErrno. --*/ { NTSTATUS status; PWINSOCK_TLS_DATA tlsData; PSOCKET_INFORMATION socket; IO_STATUS_BLOCK ioStatusBlock; int err; AFD_PARTIAL_DISCONNECT_INFO disconnectInfo; DWORD notificationEvent; WS_ENTER( "WSPShutdown", (PVOID)Handle, (PVOID)HowTo, NULL, NULL ); WS_ASSERT( lpErrno != NULL ); err = SockEnterApi( &tlsData ); if( err != NO_ERROR ) { WS_EXIT( "WSPShutdown", SOCKET_ERROR, TRUE ); *lpErrno = err; return SOCKET_ERROR; } // // Set up locals so that we know how to clean up on exit. // socket = NULL; // // Find a pointer to the socket structure corresponding to the // passed-in handle. // socket = SockFindAndReferenceSocket( Handle, TRUE ); if ( socket == NULL ) { err = WSAENOTSOCK; goto exit; } // // Acquire the lock that protect this socket. // SockAcquireSocketLockExclusive( socket ); // // If this is not a datagram socket, then it must be connected in order // for WSPShutdown() to be a legal operation. // if ( !IS_DGRAM_SOCK(socket) && !SockIsSocketConnected( socket ) ) { err = WSAENOTCONN; goto exit; } // // Translate the How parameter into the AFD disconnect information // structure. // switch ( HowTo ) { case SD_RECEIVE: disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_RECEIVE; socket->ReceiveShutdown = TRUE; notificationEvent = WSH_NOTIFY_SHUTDOWN_RECEIVE; break; case SD_SEND: disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_SEND; socket->SendShutdown = TRUE; notificationEvent = WSH_NOTIFY_SHUTDOWN_SEND; break; case SD_BOTH: disconnectInfo.DisconnectMode = AFD_PARTIAL_DISCONNECT_RECEIVE | AFD_PARTIAL_DISCONNECT_SEND; socket->ReceiveShutdown = TRUE; socket->SendShutdown = TRUE; notificationEvent = WSH_NOTIFY_SHUTDOWN_ALL; break; default: err = WSAEINVAL; goto exit; } #ifdef _AFD_SAN_SWITCH_ // // If we have a SAN socket open, close that first // if (SockSanEnabled && socket->SanSocket && socket->SanSocket->IsConnected == CONNECTED) { err = SockSanShutdown(socket, HowTo); goto exit; } #endif //_AFD_SAN_SWITCH_ // !!! temporary HACK for tp4! if ( (HowTo == 1 || HowTo == 2) && socket->AddressFamily == AF_OSI ) { disconnectInfo.DisconnectMode = AFD_ABORTIVE_DISCONNECT; } // // This routine should complete immediately, not when the remote client // acknowledges the disconnect. // disconnectInfo.Timeout = RtlConvertLongToLargeInteger( -1 ); IF_DEBUG(CLOSE) { WS_PRINT(( "starting WSPShutdown for socket %lx\n", Handle )); } // // Send the IOCTL to AFD for processing. // status = NtDeviceIoControlFile( socket->HContext.Handle, tlsData->EventHandle, NULL, // APC Routine NULL, // APC Context &ioStatusBlock, IOCTL_AFD_PARTIAL_DISCONNECT, &disconnectInfo, sizeof(disconnectInfo), NULL, // OutputBuffer 0L // OutputBufferLength ); if ( status == STATUS_PENDING ) { SockReleaseSocketLock( socket ); SockWaitForSingleObject( tlsData->EventHandle, Handle, SOCK_NEVER_CALL_BLOCKING_HOOK, SOCK_NO_TIMEOUT ); SockAcquireSocketLockExclusive( socket ); status = ioStatusBlock.Status; } if ( !NT_SUCCESS(status) ) { err = SockNtStatusToSocketError( status ); goto exit; } // // Notify the helper DLL that the socket has been shut down. // err = SockNotifyHelperDll( socket, notificationEvent ); if ( err != NO_ERROR ) { goto exit; } exit: IF_DEBUG(SHUTDOWN) { if ( err != NO_ERROR ) { WS_PRINT(( "WSPShutdown(%ld) on socket %lx (%lx) failed: %ld.\n", HowTo, Handle, socket, err )); } else { WS_PRINT(( "WSPShutdown(%ld) on socket %lx (%lx) succeeded.\n", HowTo, Handle, socket )); } } if ( socket != NULL ) { SockReleaseSocketLock( socket ); SockDereferenceSocket( socket ); } if ( err != NO_ERROR ) { WS_EXIT( "WSPShutdown", SOCKET_ERROR, TRUE ); *lpErrno = err; return SOCKET_ERROR; } WS_EXIT( "WSPShutdown", NO_ERROR, FALSE ); return NO_ERROR; } // WSPShutdown