NTSTATUS SrvReadConfig( PLWIO_SRV_CONFIG pConfig ) { NTSTATUS ntStatus = STATUS_SUCCESS; LWIO_SRV_CONFIG srvConfig = {0}; PLWIO_CONFIG_REG pReg = NULL; BOOLEAN bUsePolicy = TRUE; ntStatus = SrvInitConfig(&srvConfig); BAIL_ON_NT_STATUS(ntStatus); ntStatus = LwIoOpenConfig( "Services\\lwio\\Parameters\\Drivers\\srv", "Policy\\Services\\lwio\\Parameters\\Drivers\\srv", &pReg); if (ntStatus) { LWIO_LOG_ERROR("Failed to access device configuration [error code: %u]", ntStatus); ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; } BAIL_ON_NT_STATUS(ntStatus); /* Ignore error as it may not exist; we can still use default. */ LwIoReadConfigBoolean( pReg, "BootstrapDefaultSharePath", bUsePolicy, &srvConfig.bBootstrapDefaultSharePath); /* Ignore error as it may not exist; we can still use default. */ LwIoReadConfigDword( pReg, "MonitorIntervalMinutes", bUsePolicy, LWIO_SRV_DEFAULT_MONITOR_INTERVAL_MINS_MIN, LWIO_SRV_DEFAULT_MONITOR_INTERVAL_MINS_MAX, &srvConfig.ulMonitorIntervalMinutes); ntStatus = SrvTransferConfigContents(&srvConfig, pConfig); BAIL_ON_NT_STATUS(ntStatus); cleanup: if (pReg) { LwIoCloseConfig(pReg); } SrvFreeConfigContents(&srvConfig); return ntStatus; error: goto cleanup; }
static VOID SrvExecuteFlushAsyncCB_SMB_V2( PVOID pContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_EXEC_CONTEXT pExecContext = (PSRV_EXEC_CONTEXT)pContext; PSRV_PROTOCOL_EXEC_CONTEXT pProtocolContext = pExecContext->pProtocolContext; PSRV_FLUSH_STATE_SMB_V2 pFlushState = NULL; BOOLEAN bInLock = FALSE; pFlushState = (PSRV_FLUSH_STATE_SMB_V2)pProtocolContext->pSmb2Context->hState; LWIO_LOCK_MUTEX(bInLock, &pFlushState->mutex); if (pFlushState->pAcb->AsyncCancelContext) { IoDereferenceAsyncCancelContext(&pFlushState->pAcb->AsyncCancelContext); } pFlushState->pAcb = NULL; LWIO_UNLOCK_MUTEX(bInLock, &pFlushState->mutex); ntStatus = SrvProdConsEnqueue(gProtocolGlobals_SMB_V2.pWorkQueue, pContext); if (ntStatus != STATUS_SUCCESS) { LWIO_LOG_ERROR("Failed to enqueue execution context [status:0x%x]", ntStatus); SrvReleaseExecContext(pExecContext); } }
static VOID SrvDriverShutdown( IN IO_DRIVER_HANDLE hDriver ) { NTSTATUS ntStatus = STATUS_SUCCESS; ntStatus = SrvShutdown(); BAIL_ON_NT_STATUS(ntStatus); if (gSMBSrvGlobals.hDevice) { IoDeviceDelete(&gSMBSrvGlobals.hDevice); } cleanup: return; error: if (ntStatus) { LWIO_LOG_ERROR("[srv] driver failed to stop. [code: %d]", ntStatus); } goto cleanup; }
NTSTATUS SrvStatsConfigRead( PSRV_STATISTICS_CONFIG pConfig ) { NTSTATUS ntStatus = STATUS_SUCCESS; SRV_STATISTICS_CONFIG config = { 0 }; PLWIO_CONFIG_REG pReg = NULL; BOOLEAN bUsePolicy = TRUE; ntStatus = SrvStatsConfigInitContents(&config); BAIL_ON_NT_STATUS(ntStatus); ntStatus = LwIoOpenConfig( "Services\\lwio\\Parameters\\Drivers\\srv\\statistics", "Policy\\Services\\lwio\\Parameters\\Drivers\\srv\\statistics", &pReg); if (ntStatus) { LWIO_LOG_ERROR( "Failed to access device statistics configuration [error code: %u]", ntStatus); ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; } BAIL_ON_NT_STATUS(ntStatus); /* Ignore error as it may not exist; we can still use default. */ LwIoReadConfigString( pReg, "Path", bUsePolicy, &config.pszProviderPath); LwIoReadConfigBoolean( pReg, "EnableLogging", bUsePolicy, &config.bEnableLogging); ntStatus = SrvStatsConfigTransferContents(&config, pConfig); BAIL_ON_NT_STATUS(ntStatus); cleanup: if (pReg) { LwIoCloseConfig(pReg); } return ntStatus; error: SrvStatsConfigFreeContents(&config); goto cleanup; }
static NTSTATUS SrvShareBootstrapDiskRoot( IN OUT PLWIO_SRV_SHARE_ENTRY_LIST pShareList ) { NTSTATUS ntStatus = STATUS_SUCCESS; wchar16_t wszFileRootName[] = {'C','$',0}; PSTR pszDefaultSharePath = NULL; PWSTR pwszFileSystemRoot = NULL; PSRV_SHARE_INFO pShareInfo = NULL; ntStatus = SrvShareFindByName( pShareList, &wszFileRootName[0], &pShareInfo); if (ntStatus == STATUS_NOT_FOUND) { wchar16_t wszDesc[] = {'D','e','f','a','u','l','t',' ','S','h','a','r','e',0}; wchar16_t wszServiceType[] = LWIO_SRV_SHARE_STRING_ID_DISK_W; ntStatus = SrvGetDefaultSharePath(&pszDefaultSharePath); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvMbsToWc16s(pszDefaultSharePath, &pwszFileSystemRoot); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvCreateDefaultSharePath(pwszFileSystemRoot); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvShareAdd( pShareList, &wszFileRootName[0], pwszFileSystemRoot, &wszDesc[0], NULL, 0, &wszServiceType[0], 0); } BAIL_ON_NT_STATUS(ntStatus); cleanup: SRV_SAFE_FREE_MEMORY(pszDefaultSharePath); SRV_SAFE_FREE_MEMORY(pwszFileSystemRoot); return ntStatus; error: LWIO_LOG_ERROR("Failed to bootstrap default shares. [error code: %d]", ntStatus); goto cleanup; }
static void smb_display_status_1( PCSTR pszId, OM_uint32 code, int type ) { OM_uint32 min_stat; gss_buffer_desc msg; OM_uint32 msg_ctx; if ( code == 0 ) { return; } msg_ctx = 0; while (1) { (void) gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg); switch(code) { #ifdef WIN32 case SEC_E_OK: case SEC_I_CONTINUE_NEEDED: #else case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: #endif LWIO_LOG_VERBOSE("GSS-API error calling %s: %d (%s)\n", pszId, code, LWIO_SAFE_LOG_STRING((char *)msg.value)); break; default: LWIO_LOG_ERROR("GSS-API error calling %s: %d (%s)\n", pszId, code, LWIO_SAFE_LOG_STRING((char *)msg.value)); } (void) gss_release_buffer(&min_stat, &msg); if (!msg_ctx) break; } }
static NTSTATUS SrvShareBootstrapNamedPipeRoot( IN OUT PLWIO_SRV_SHARE_ENTRY_LIST pShareList ) { NTSTATUS ntStatus = STATUS_SUCCESS; wchar16_t wszPipeRootName[] = {'I','P','C','$',0}; PSRV_SHARE_INFO pShareInfo = NULL; ntStatus = SrvShareFindByName( pShareList, &wszPipeRootName[0], &pShareInfo); if (ntStatus == STATUS_NOT_FOUND) { wchar16_t wszPipeSystemRoot[] = LWIO_SRV_PIPE_SYSTEM_ROOT_W; wchar16_t wszServiceType[] = LWIO_SRV_SHARE_STRING_ID_IPC_W; wchar16_t wszDesc[] = {'R','e','m','o','t','e',' ','I','P','C',0}; ntStatus = SrvShareAdd( pShareList, &wszPipeRootName[0], &wszPipeSystemRoot[0], &wszDesc[0], NULL, 0, &wszServiceType[0], 0); BAIL_ON_NT_STATUS(ntStatus); } cleanup: if (pShareInfo) { SrvShareReleaseInfo(pShareInfo); } return ntStatus; error: LWIO_LOG_ERROR("Failed to bootstrap default IPC$ shares. [error code: %d]", ntStatus); goto cleanup; }
VOID RdrTree2Release( RDR_TREE2 *pTree ) { BOOLEAN bInLock = FALSE; LW_TASK_EVENT_MASK dummy = 0; LONG64 llDummy = 0; LWIO_LOCK_MUTEX(bInLock, &pTree->pSession->mutex); assert(pTree->refCount > 0); if (--pTree->refCount == 0) { if (pTree->state != RDR_TREE_STATE_READY || !RdrSocketIsValid(pTree->pSession->pSocket)) { RdrTree2Unlink(pTree); LWIO_UNLOCK_MUTEX(bInLock, &pTree->pSession->mutex); RdrTree2Free(pTree); } else { LWIO_LOG_VERBOSE("Tree %p is eligible for reaping", pTree); LWIO_UNLOCK_MUTEX(bInLock, &pTree->pSession->mutex); if (LwRtlCreateTask( gRdrRuntime.pThreadPool, &pTree->pTimeout, gRdrRuntime.pTreeTimerGroup, RdrTree2Timeout, pTree) == STATUS_SUCCESS) { LwRtlWakeTask(pTree->pTimeout); } else { LWIO_LOG_ERROR("Could not create timer for tree %p; disconnecting immediately"); RdrTree2Timeout(NULL, pTree, LW_TASK_EVENT_TIME, &dummy, &llDummy); } } } else { LWIO_UNLOCK_MUTEX(bInLock, &pTree->pSession->mutex); } }
NTSTATUS PvfsMapUnixErrnoToNtStatus( int err ) { NTSTATUS ntError = LwErrnoToNtStatus(err); if (ntError == (NTSTATUS)-1) { LWIO_LOG_ERROR( "%s: Unable to map Unix errno (%d) to an NTSTATUS error.\n", PVFS_LOG_HEADER, err); } return ntError; }
static VOID SrvFreeOpenState( PSRV_OPEN_STATE_SMB_V1 pOpenState ) { if (pOpenState->pAcb && pOpenState->pAcb->AsyncCancelContext) { IoDereferenceAsyncCancelContext( &pOpenState->pAcb->AsyncCancelContext); } if (pOpenState->pEcpList) { IoRtlEcpListFree(&pOpenState->pEcpList); } // TODO: Free the following if set // pSecurityDescriptor; // pSecurityQOS; if (pOpenState->pFilename) { if (pOpenState->pFilename->FileName) { SrvFreeMemory(pOpenState->pFilename->FileName); } SrvFreeMemory(pOpenState->pFilename); } if (pOpenState->hFile) { IoCloseFile(pOpenState->hFile); } if (pOpenState->bRemoveFileFromTree) { NTSTATUS ntStatus2 = 0; SrvFileResetOplockState(pOpenState->pFile); ntStatus2 = SrvTreeRemoveFile( pOpenState->pTree, pOpenState->pFile->fid); if (ntStatus2) { LWIO_LOG_ERROR("Failed to remove file from tree [Tid:%d][Fid:%d][code:%d]", pOpenState->pTree->tid, pOpenState->pFile->fid, ntStatus2); } } if (pOpenState->pFile) { SrvFileRelease(pOpenState->pFile); } if (pOpenState->pTree) { SrvTreeRelease(pOpenState->pTree); } if (pOpenState->pMutex) { pthread_mutex_destroy(&pOpenState->mutex); } SrvFreeMemory(pOpenState); }
static NTSTATUS SrvShareDbCreate( VOID ) { NTSTATUS ntStatus = 0; PSRV_SHARE_DB_CONTEXT pDbContext = NULL; PSTR pszError = NULL; BOOLEAN bExists = FALSE; PCSTR pszShareDBPath = LWIO_SRV_SHARE_DB; PCSTR pszShareDBDir = LWIO_SRV_DB_DIR; BOOLEAN bInLock = FALSE; ntStatus = SMBCheckFileExists(pszShareDBPath, &bExists); BAIL_ON_NT_STATUS(ntStatus); // TODO: Implement an upgrade scenario if (bExists) { goto cleanup; } ntStatus = SMBCheckDirectoryExists(pszShareDBDir, &bExists); BAIL_ON_NT_STATUS(ntStatus); if (!bExists) { mode_t cacheDirMode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; /* Allow go+rx to the base folder */ ntStatus = SMBCreateDirectory(pszShareDBDir, cacheDirMode); BAIL_ON_NT_STATUS(ntStatus); } /* restrict access to u+rwx to the db folder */ ntStatus = SMBChangeOwnerAndPermissions(pszShareDBDir, 0, 0, S_IRWXU); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvShareDbAcquireContext(&pDbContext); BAIL_ON_NT_STATUS(ntStatus); LWIO_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &gShareRepository_lwshare.dbMutex); ntStatus = sqlite3_exec( pDbContext->pDbHandle, DB_QUERY_CREATE_SHARES_TABLE, NULL, NULL, &pszError); BAIL_ON_LWIO_SRV_SQLITE_ERROR_DB(ntStatus, pDbContext->pDbHandle); ntStatus = SMBChangeOwnerAndPermissions( pszShareDBPath, 0, 0, S_IRWXU); BAIL_ON_NT_STATUS(ntStatus); cleanup: if (pDbContext) { SrvShareDbReleaseContext(pDbContext); } LWIO_UNLOCK_RWMUTEX(bInLock, &gShareRepository_lwshare.dbMutex); return ntStatus; error: if (pszError) { LWIO_LOG_ERROR("%s", pszError); sqlite3_free(pszError); } goto cleanup; }
static VOID IopIrpCompleteInternal( IN OUT PIRP pIrp, IN BOOLEAN IsAsyncCompletion ) { PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp); IopIrpAcquireCancelLock(pIrp); LWIO_ASSERT_MSG(IS_BOTH_OR_NEITHER(IsAsyncCompletion, IsSetFlag(irpInternal->Flags, IRP_FLAG_PENDING)), "IRP pending state is inconsistent."); LWIO_ASSERT_MSG(IsSetFlag(irpInternal->Flags, IRP_FLAG_DISPATCHED), "IRP cannot be completed unless it was properly dispatched."); LWIO_ASSERT_MSG(!IsSetFlag(irpInternal->Flags, IRP_FLAG_COMPLETE), "IRP cannot be completed more than once."); // // Note that the IRP may be CANCEL_PENDING or CANCELLED, but that // is ok. In fact, completion may have been called in response // to cancellation. // SetFlag(irpInternal->Flags, IRP_FLAG_COMPLETE); IopIrpReleaseCancelLock(pIrp); IopFileObjectRemoveDispatched(pIrp->FileHandle, pIrp->Type); LWIO_ASSERT(IsValidStatusForIrpType(pIrp->IoStatusBlock.Status, pIrp->Type)); switch (pIrp->Type) { case IRP_TYPE_CREATE: case IRP_TYPE_CREATE_NAMED_PIPE: if ((STATUS_SUCCESS == pIrp->IoStatusBlock.Status) || (STATUS_OPLOCK_BREAK_IN_PROGRESS == pIrp->IoStatusBlock.Status)) { // Handle special success processing having to do with file handle. // ISSUE-May not need lock since it should be only reference IopFileObjectLock(pIrp->FileHandle); SetFlag(pIrp->FileHandle->Flags, FILE_OBJECT_FLAG_CREATE_DONE); IopFileObjectUnlock(pIrp->FileHandle); IopFileObjectReference(pIrp->FileHandle); if (IsAsyncCompletion && irpInternal->Completion.IsAsyncCall) { *irpInternal->Completion.Async.OpOut.Create.pFileHandle = pIrp->FileHandle; } } break; case IRP_TYPE_CLOSE: if (STATUS_SUCCESS == pIrp->IoStatusBlock.Status) { PIO_FILE_OBJECT pFileObject = NULL; SetFlag(pIrp->FileHandle->Flags, FILE_OBJECT_FLAG_CLOSE_DONE); // Note that we must delete the reference from the create // w/o removing the file object value from the IRP (which // will be removed when the IRP is freed). pFileObject = pIrp->FileHandle; IopFileObjectDereference(&pFileObject); } else { LWIO_LOG_ERROR("Unable to close file object, status = 0x%08x", pIrp->IoStatusBlock.Status); } break; case IRP_TYPE_READ: case IRP_TYPE_WRITE: if (IRP_ZCT_OPERATION_PREPARE == pIrp->Args.ReadWrite.ZctOperation) { if (STATUS_SUCCESS == pIrp->IoStatusBlock.Status) { LWIO_ASSERT(pIrp->Args.ReadWrite.ZctCompletionContext); if (IsAsyncCompletion && irpInternal->Completion.IsAsyncCall) { PIRP pCompletionIrp = irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionIrp; PVOID pCompletionContext = IopIrpSaveZctIrp( pIrp->FileHandle, pCompletionIrp, pIrp->Args.ReadWrite.ZctCompletionContext); *irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionContext = pCompletionContext; } } if (irpInternal->Completion.IsAsyncCall) { IopIrpDereference(&irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionIrp); } } break; } if (IsAsyncCompletion) { if (irpInternal->Completion.IsAsyncCall) { *irpInternal->Completion.Async.pIoStatusBlock = pIrp->IoStatusBlock; irpInternal->Completion.Async.Callback( irpInternal->Completion.Async.CallbackContext); } else { LwRtlSetEvent(irpInternal->Completion.Sync.Event); } // // Release reference from IoIrpMarkPending(). // IopIrpDereference(&pIrp); } }
static NTSTATUS PvfsDoZctSpliceWriteIo( IN PPVFS_ZCT_CONTEXT pZctContext, IN ULONG BufferLength, IN LONG64 Offset, OUT PULONG pBytesWritten ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; LONG64 currentOffset = Offset; ULONG totalBytesWritten = 0; while (totalBytesWritten < BufferLength) { ULONG bytesWritten = 0; // Using SPLICE_F_NONBLOCK because would block // on non-blocking pipe otherwise. ntError = PvfsSysSplice(pZctContext->PipeFds[0], NULL, pZctContext->pCcb->fd, ¤tOffset, BufferLength - totalBytesWritten, SPLICE_F_MOVE | SPLICE_F_NONBLOCK, &bytesWritten); if (ntError == STATUS_MORE_PROCESSING_REQUIRED) { continue; } if (ntError == STATUS_RETRY) { // splice returned EAGAIN. This normally // happens if the pipe buffer is not bit enough. // This should never happen due to the splice // pipe buffer check in PvfsCreateZctContext. // In write completion, there is nothing we can // do about it except to log. LWIO_LOG_ERROR("Unexpected splice failure with EAGAIN/STATUS_RETRY"); } BAIL_ON_NT_STATUS(ntError); /* Check for EOF */ if (bytesWritten == 0) { break; } totalBytesWritten += bytesWritten; } /* Can only get here is the loop was completed successfully */ cleanup: *pBytesWritten = totalBytesWritten; return ntError; error: totalBytesWritten = 0; goto cleanup; }
static PVOID SrvTimerMain( IN PVOID pData ) { NTSTATUS status = 0; PSRV_TIMER_CONTEXT pContext = (PSRV_TIMER_CONTEXT)pData; PSRV_TIMER_REQUEST pTimerRequest = NULL; LONG64 llCurTime = 0LL; BOOLEAN bInLock = FALSE; LWIO_LOG_DEBUG("Srv timer starting"); LWIO_LOCK_MUTEX(bInLock, &pContext->mutex); while (!SrvTimerMustStop_inlock(pContext)) { int errCode = 0; BOOLEAN bRetryWait = FALSE; // If we have a current timer request, check if it is time to service it if (pTimerRequest) { status = WireGetCurrentNTTime(&llCurTime); BAIL_ON_NT_STATUS(status); if (llCurTime >= pTimerRequest->llExpiry && !pTimerRequest->bCanceled) { SrvTimerDetachRequest_inlock(pContext, pTimerRequest); LWIO_UNLOCK_MUTEX(bInLock, &pContext->mutex); if (pTimerRequest->pfnTimerExpiredCB) { // Timer has not been canceled pTimerRequest->pfnTimerExpiredCB( pTimerRequest, pTimerRequest->pUserData); } LWIO_LOCK_MUTEX(bInLock, &pContext->mutex); } SrvTimerRelease(pTimerRequest); pTimerRequest = NULL; } // Get the next timer request in queue status = SrvTimerGetNextRequest_inlock(pContext, &pTimerRequest); if (status == STATUS_NOT_FOUND) { // If the queue is empty wait for a day or until a request arrives struct timespec tsLong = { .tv_sec = time(NULL) + 86400, .tv_nsec = 0 }; status = STATUS_SUCCESS; do { bRetryWait = FALSE; errCode = pthread_cond_timedwait( &pContext->event, &pContext->mutex, &tsLong); if (errCode == ETIMEDOUT) { if (time(NULL) < tsLong.tv_sec) { bRetryWait = TRUE; continue; } break; } status = LwErrnoToNtStatus(errCode); BAIL_ON_NT_STATUS(status); } while (bRetryWait && !SrvTimerMustStop_inlock(pContext)); continue; } BAIL_ON_NT_STATUS(status); // At this point, we have a timer request - wait for its specified time do { struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; bRetryWait = FALSE; status = WireNTTimeToTimeSpec(pTimerRequest->llExpiry, &ts); BAIL_ON_NT_STATUS(status); errCode = pthread_cond_timedwait( &pContext->event, &pContext->mutex, &ts); if (errCode == ETIMEDOUT) { status = WireGetCurrentNTTime(&llCurTime); BAIL_ON_NT_STATUS(status); if (llCurTime < pTimerRequest->llExpiry) { bRetryWait = TRUE; continue; } break; } status = LwErrnoToNtStatus(errCode); BAIL_ON_NT_STATUS(status); } while (bRetryWait && !SrvTimerMustStop_inlock(pContext)); } cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pContext->mutex); if (pTimerRequest) { SrvTimerRelease(pTimerRequest); } LWIO_LOG_DEBUG("Srv timer stopping"); return NULL; error: LWIO_LOG_ERROR("Srv timer stopping due to error [%d]", status); goto cleanup; } static NTSTATUS SrvTimerGetNextRequest_inlock( IN PSRV_TIMER_CONTEXT pContext, OUT PSRV_TIMER_REQUEST* ppTimerRequest ) { NTSTATUS status = STATUS_SUCCESS; PSRV_TIMER_REQUEST pTimerRequest = NULL; if (!pContext->pRequests) { status = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(status); } pTimerRequest = pContext->pRequests; InterlockedIncrement(&pTimerRequest->refCount); *ppTimerRequest = pTimerRequest; cleanup: return status; error: *ppTimerRequest = NULL; goto cleanup; } static NTSTATUS SrvTimerDetachRequest_inlock( IN OUT PSRV_TIMER_CONTEXT pContext, IN OUT PSRV_TIMER_REQUEST pTimerRequest ) { if (pTimerRequest->pPrev) { pTimerRequest->pPrev->pNext = pTimerRequest->pNext; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = pTimerRequest->pPrev; } } else { pContext->pRequests = pTimerRequest->pNext; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = NULL; } } pTimerRequest->pPrev = NULL; pTimerRequest->pNext = NULL; // Removed from timer queue InterlockedDecrement(&pTimerRequest->refCount); return STATUS_SUCCESS; } NTSTATUS SrvTimerPostRequestSpecific( IN PSRV_TIMER pTimer, IN LONG64 llExpiry, IN PVOID pUserData, IN PFN_SRV_TIMER_CALLBACK pfnTimerExpiredCB, OUT PSRV_TIMER_REQUEST* ppTimerRequest ) { NTSTATUS status = STATUS_SUCCESS; PSRV_TIMER_REQUEST pTimerRequest = NULL; PSRV_TIMER_REQUEST pTimerIter = NULL; PSRV_TIMER_REQUEST pPrev = NULL; BOOLEAN bInLock = FALSE; if (!llExpiry) { status = STATUS_INVALID_PARAMETER_1; BAIL_ON_NT_STATUS(status); } if (!pfnTimerExpiredCB) { status = STATUS_INVALID_PARAMETER_3; BAIL_ON_NT_STATUS(status); } status = SrvAllocateMemory( sizeof(SRV_TIMER_REQUEST), (PVOID*)&pTimerRequest); BAIL_ON_NT_STATUS(status); pTimerRequest->refCount = 1; pTimerRequest->llExpiry = llExpiry; pTimerRequest->pUserData = pUserData; pTimerRequest->pfnTimerExpiredCB = pfnTimerExpiredCB; pTimerRequest->bCanceled = FALSE; LWIO_LOCK_MUTEX(bInLock, &pTimer->context.mutex); for (pTimerIter = pTimer->context.pRequests; pTimerIter && (pTimerIter->llExpiry <= llExpiry); pPrev = pTimerIter, pTimerIter = pTimerIter->pNext); if (!pPrev) { pTimerRequest->pNext = pTimer->context.pRequests; if (pTimer->context.pRequests) { pTimer->context.pRequests->pPrev = pTimerRequest; } pTimer->context.pRequests = pTimerRequest; } else { pTimerRequest->pNext = pPrev->pNext; pTimerRequest->pPrev = pPrev; pPrev->pNext = pTimerRequest; if (pTimerRequest->pNext) { pTimerRequest->pNext->pPrev = pTimerRequest; } } // +1 for timer queue InterlockedIncrement(&pTimerRequest->refCount); LWIO_UNLOCK_MUTEX(bInLock, &pTimer->context.mutex); pthread_cond_signal(&pTimer->context.event); // +1 for caller InterlockedIncrement(&pTimerRequest->refCount); *ppTimerRequest = pTimerRequest; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pTimer->context.mutex); if (pTimerRequest) { SrvTimerRelease(pTimerRequest); } return status; error: *ppTimerRequest = NULL; goto cleanup; }
NTSTATUS SrvProcessNotify_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; ULONG iMsg = pCtxSmb2->iMsg; PSRV_MESSAGE_SMB_V2 pSmbRequest = &pCtxSmb2->pRequests[iMsg]; PLWIO_SRV_SESSION_2 pSession = NULL; PLWIO_SRV_TREE_2 pTree = NULL; BOOLEAN bInLock = FALSE; PSRV_NOTIFY_STATE_SMB_V2 pNotifyState = NULL; PLWIO_ASYNC_STATE pAsyncState = NULL; BOOLEAN bUnregisterAsync = FALSE; PSRV_NOTIFY_REQUEST_STATE_SMB_V2 pNotifyRequestState = NULL; pNotifyRequestState = (PSRV_NOTIFY_REQUEST_STATE_SMB_V2)pCtxSmb2->hState; if (pNotifyRequestState) { InterlockedIncrement(&pNotifyRequestState->refCount); } else { PSMB2_NOTIFY_CHANGE_HEADER pRequestHeader = NULL; // Do not free ntStatus = SrvConnection2FindSession_SMB_V2( pCtxSmb2, pConnection, pSmbRequest->pHeader->ullSessionId, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSession2Info(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSession2FindTree_SMB_V2( pCtxSmb2, pSession, pSmbRequest->pHeader->ulTid, &pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMB2UnmarshalNotifyRequest(pSmbRequest, &pRequestHeader); BAIL_ON_NT_STATUS(ntStatus); SRV_LOG_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_2, pSmbRequest->pHeader->command, "Change notify request params: " "command(%u),uid(%llu),cmd-seq(%llu),pid(%u),tid(%u)," "credits(%u),flags(0x%x),chain-offset(%u)," "file-id(persistent:0x%x,volatile:0x%x)," "flags(0x%x),completion-filter(%u),output-buffer-length(%u)", pSmbRequest->pHeader->command, (long long)pSmbRequest->pHeader->ullSessionId, (long long)pSmbRequest->pHeader->ullCommandSequence, pSmbRequest->pHeader->ulPid, pSmbRequest->pHeader->ulTid, pSmbRequest->pHeader->usCredits, pSmbRequest->pHeader->ulFlags, pSmbRequest->pHeader->ulChainOffset, (long long)pRequestHeader->fid.ullPersistentId, (long long)pRequestHeader->fid.ullVolatileId, pRequestHeader->usFlags, pRequestHeader->ulCompletionFilter, pRequestHeader->ulOutputBufferLength); ntStatus = SrvBuildNotifyRequestState_SMB_V2( pRequestHeader, &pNotifyRequestState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb2->hState = pNotifyRequestState; InterlockedIncrement(&pNotifyRequestState->refCount); pCtxSmb2->pfnStateRelease = &SrvReleaseNotifyRequestStateHandle_SMB_V2; ntStatus = SrvTree2FindFile_SMB_V2( pCtxSmb2, pTree, &pRequestHeader->fid, &pNotifyRequestState->pFile); BAIL_ON_NT_STATUS(ntStatus); } LWIO_LOCK_MUTEX(bInLock, &pNotifyRequestState->mutex); switch (pNotifyRequestState->stage) { case SRV_NOTIFY_STAGE_SMB_V2_INITIAL: if (pNotifyRequestState->pRequestHeader->ulOutputBufferLength > SMB_CN_MAX_BUFFER_SIZE) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } // A change notify request can occur as the only message in // a request, or the last in a chained request if (pCtxSmb2->iMsg != (pCtxSmb2->ulNumRequests - 1)) { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvConnection2CreateAsyncState( pConnection, COM2_NOTIFY, &SrvCancelNotifyState_SMB_V2, &SrvNotifyStateReleaseHandle_SMB_V2, &pAsyncState); BAIL_ON_NT_STATUS(ntStatus); bUnregisterAsync = TRUE; ntStatus = SrvNotifyCreateState_SMB_V2( pAsyncState->ullAsyncId, pExecContext->pConnection, pCtxSmb2->pSession, pCtxSmb2->pTree, pNotifyRequestState->pFile, pSmbRequest->pHeader->usEpoch, pSmbRequest->pHeader->ullCommandSequence, pSmbRequest->pHeader->ulPid, pNotifyRequestState->pRequestHeader->ulCompletionFilter, (pNotifyRequestState->pRequestHeader->usFlags & SMB2_NOTIFY_FLAGS_WATCH_TREE), pNotifyRequestState->pRequestHeader->ulOutputBufferLength, &pNotifyState); BAIL_ON_NT_STATUS(ntStatus); pAsyncState->hAsyncState = SrvNotifyStateAcquire_SMB_V2(pNotifyState); pNotifyRequestState->stage = SRV_NOTIFY_STAGE_SMB_V2_ATTEMPT_IO; // intentional fall through case SRV_NOTIFY_STAGE_SMB_V2_ATTEMPT_IO: ntStatus = SrvExecuteChangeNotify_SMB_V2( pExecContext, pNotifyState); switch (ntStatus) { case STATUS_PENDING: { // TODO: Might have to cancel the entire operation // NTSTATUS ntStatus2 = SrvBuildInterimResponse_SMB_V2( pExecContext, pNotifyState->ullAsyncId); if (ntStatus2 != STATUS_SUCCESS) { LWIO_LOG_ERROR( "Failed to create interim response [code:0x%8x]", ntStatus2); } bUnregisterAsync = FALSE; } break; case STATUS_SUCCESS: // completed synchronously; remove asynchronous state // SrvConnection2RemoveAsyncState( pConnection, pAsyncState->ullAsyncId); pNotifyState->ullAsyncId = 0LL; bUnregisterAsync = FALSE; break; default: break; } BAIL_ON_NT_STATUS(ntStatus); pNotifyRequestState->stage = SRV_NOTIFY_STAGE_SMB_V2_BUILD_RESPONSE; // intentional fall through case SRV_NOTIFY_STAGE_SMB_V2_BUILD_RESPONSE: ntStatus = SrvBuildNotifyResponse_SMB_V2( pExecContext, pNotifyState); BAIL_ON_NT_STATUS(ntStatus); pNotifyRequestState->stage = SRV_NOTIFY_STAGE_SMB_V2_DONE; // intentional fall through case SRV_NOTIFY_STAGE_SMB_V2_DONE: break; } cleanup: if (pNotifyRequestState) { LWIO_UNLOCK_MUTEX(bInLock, &pNotifyRequestState->mutex); SrvReleaseNotifyRequestState_SMB_V2(pNotifyRequestState); } if (pNotifyState) { if (bUnregisterAsync) { SrvConnection2RemoveAsyncState( pConnection, pNotifyState->ullAsyncId); } SrvNotifyStateRelease_SMB_V2(pNotifyState); } if (pAsyncState) { SrvAsyncStateRelease(pAsyncState); } if (pTree) { SrvTree2Release(pTree); } if (pSession) { SrvSession2Release(pSession); } return ntStatus; error: switch (ntStatus) { case STATUS_PENDING: break; default: if (pNotifyState) { SrvReleaseNotifyStateAsync_SMB_V2(pNotifyState); } break; } goto cleanup; }
NTSTATUS SrvShareDbAcquireContext( PSRV_SHARE_DB_CONTEXT* ppDbContext ) { NTSTATUS ntStatus = 0; BOOLEAN bInLock = FALSE; PSRV_SHARE_DB_GLOBALS pGlobals = &gShareRepository_lwshare; PSRV_SHARE_DB_CONTEXT pDbContext = NULL; LWIO_LOCK_MUTEX(bInLock, &pGlobals->mutex); if (pGlobals->ulNumDbContexts) { pDbContext = pGlobals->pDbContextList; pGlobals->pDbContextList = pGlobals->pDbContextList->pNext; pDbContext->pNext = NULL; pGlobals->ulNumDbContexts--; LWIO_UNLOCK_MUTEX(bInLock, &pGlobals->mutex); } else { PCSTR pszShareDbPath = LWIO_SRV_SHARE_DB; ntStatus = SrvAllocateMemory( sizeof(SRV_SHARE_DB_CONTEXT), (PVOID*)&pDbContext); BAIL_ON_NT_STATUS(ntStatus); ntStatus = sqlite3_open( pszShareDbPath, &pDbContext->pDbHandle); if (ntStatus) { LWIO_LOG_ERROR("Sqlite3 Error (code: %d): %s", ntStatus, "Failed to open database handle"""); ntStatus = STATUS_INTERNAL_DB_ERROR; } BAIL_ON_NT_STATUS(ntStatus); } *ppDbContext = pDbContext; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pGlobals->mutex); return ntStatus; error: *ppDbContext = NULL; if (pDbContext) { SrvShareDbFreeContext(pDbContext); } goto cleanup; }
static NTSTATUS SrvGetDefaultSharePath( PSTR* ppszFileSystemRoot ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSTR pszDefaultSharePath = NULL; PSTR pszFileSystemRoot = NULL; PSTR pszCursor = NULL; BOOLEAN bUsePolicy = TRUE; CHAR szTmpFSRoot[] = LWIO_SRV_FILE_SYSTEM_ROOT_A; PLWIO_CONFIG_REG pReg = NULL; ntStatus = LwIoOpenConfig( "Services\\lwio\\Parameters\\Drivers\\srv", "Policy\\Services\\lwio\\Parameters\\Drivers\\srv", &pReg); BAIL_ON_NT_STATUS(ntStatus); ntStatus = LwIoReadConfigString( pReg, "DefaultSharePath", bUsePolicy, &pszDefaultSharePath); BAIL_ON_NT_STATUS(ntStatus); if (IsNullOrEmptyString(pszDefaultSharePath) || ((*pszDefaultSharePath != '/') && (*pszDefaultSharePath != '\\'))) { LWIO_LOG_ERROR("Error: Default share path configured is not an absolute path"); ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvAllocateStringPrintf( &pszFileSystemRoot, "%s%s%s", &szTmpFSRoot[0], (((szTmpFSRoot[strlen(&szTmpFSRoot[0])-1] == '/') || (szTmpFSRoot[strlen(&szTmpFSRoot[0])-1] == '\\')) ? "" : "\\"), IsNullOrEmptyString(pszDefaultSharePath+1) ? "" : pszDefaultSharePath+1); BAIL_ON_NT_STATUS(ntStatus); for (pszCursor = pszFileSystemRoot; pszCursor && *pszCursor; pszCursor++) { if (*pszCursor == '/') { *pszCursor = '\\'; } } *ppszFileSystemRoot = pszFileSystemRoot; cleanup: if (pReg) { LwIoCloseConfig(pReg); } RTL_FREE(&pszDefaultSharePath); return ntStatus; error: *ppszFileSystemRoot = NULL; LWIO_LOG_ERROR("Failed to access device configuration [error code: %u]", ntStatus); ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; goto cleanup; }
static NTSTATUS PvfsRenameFile( PPVFS_CCB pCcb, PPVFS_FILE_NAME pNewFileName ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_CB_TABLE scbTable = &gPvfsDriverState.ScbTable; PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL; PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL; BOOLEAN renameLock = FALSE; BOOLEAN targetBucketLock = FALSE; BOOLEAN currentBucketLock = FALSE; PPVFS_FCB pFcb = NULL; PLW_LIST_LINKS scbCursorLink = NULL; PPVFS_SCB scbCursor = NULL; BOOLEAN scbMutexLock = FALSE; BOOLEAN fcbListLocked = FALSE; PPVFS_FILE_NAME origTargetFileName = NULL; PPVFS_FILE_NAME scbCursorFileName = NULL; PSTR origFullStreamName = NULL; PSTR newFullStreamName = NULL; // The CCB holds out reference down the chain so no need to take a new one pFcb = pCcb->pScb->pOwnerFcb; ntError = PvfsAllocateFileNameFromScb(&origTargetFileName, pCcb->pScb); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &scbTable->rwLock); LWIO_LOCK_RWMUTEX_SHARED(fcbListLocked, &pFcb->rwScbLock); ntError = PvfsRenameFCB(pFcb, pCcb, pNewFileName); BAIL_ON_NT_STATUS(ntError); for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL); scbCursorLink; scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink)) { scbCursor = LW_STRUCT_FROM_FIELD( scbCursorLink, PVFS_SCB, FcbList); ntError = PvfsAllocateFileNameFromScb(&scbCursorFileName, scbCursor); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &newFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsRenameBaseFileName( scbCursorFileName, PvfsGetCStringBaseFileName(origTargetFileName)); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &origFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); pCurrentBucket = scbCursor->BaseControlBlock.pBucket; ntError = PvfsCbTableGetBucket(&pTargetBucket, scbTable, newFullStreamName); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLock, &pCurrentBucket->rwLock); if (pCurrentBucket != pTargetBucket) { // Will be moved to a new bucket in the table LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLock, &pTargetBucket->rwLock); } ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)scbCursor, origFullStreamName); LWIO_ASSERT(STATUS_SUCCESS == ntError); ntError = PvfsCbTableAdd_inlock( pTargetBucket, newFullStreamName, (PPVFS_CONTROL_BLOCK)scbCursor); if (STATUS_SUCCESS != ntError) { LWIO_LOG_ERROR( "Failed to rename stream \"%s\" (%s)\n", newFullStreamName, LwNtStatusToName(ntError)); } LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } } error: LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_RWMUTEX(fcbListLocked, &pFcb->rwScbLock); LWIO_UNLOCK_RWMUTEX(renameLock, &scbTable->rwLock); if (origTargetFileName) { PvfsFreeFileName(origTargetFileName); } if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } return ntError; }
static VOID SrvFreeDeleteState( PSRV_DELETE_STATE_SMB_V1 pDeleteState ) { if (pDeleteState->pAcb && pDeleteState->pAcb->AsyncCancelContext) { IoDereferenceAsyncCancelContext( &pDeleteState->pAcb->AsyncCancelContext); } if (pDeleteState->pEcpList) { IoRtlEcpListFree(&pDeleteState->pEcpList); } if (pDeleteState->hSearchSpace) { NTSTATUS ntStatus2 = 0; ntStatus2 = SrvFinderCloseSearchSpace( pDeleteState->pSession->hFinderRepository, pDeleteState->usSearchId); if (ntStatus2) { LWIO_LOG_ERROR("Failed to close search space [Id:%d][code:%d]", pDeleteState->usSearchId, ntStatus2); } SrvFinderReleaseSearchSpace(pDeleteState->hSearchSpace); } if (pDeleteState->pTree) { SrvTreeRelease(pDeleteState->pTree); } if (pDeleteState->pSession) { SrvSessionRelease(pDeleteState->pSession); } if (pDeleteState->pwszFilesystemPath) { SrvFreeMemory(pDeleteState->pwszFilesystemPath); } if (pDeleteState->pwszSearchPattern2) { SrvFreeMemory(pDeleteState->pwszSearchPattern2); } if (pDeleteState->hFile) { IoCloseFile(pDeleteState->hFile); } if (pDeleteState->pData) { SrvFreeMemory(pDeleteState->pData); } SRV_FREE_UNICODE_STRING(&pDeleteState->fileName.Name); if (pDeleteState->pMutex) { pthread_mutex_destroy(&pDeleteState->mutex); } SrvFreeMemory(pDeleteState); }
static VOID SrvNotifyAsyncCB( PVOID pContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_EXEC_CONTEXT pExecContext = NULL; BOOLEAN bInLock = FALSE; PSRV_CHANGE_NOTIFY_STATE_SMB_V1 pNotifyState = (PSRV_CHANGE_NOTIFY_STATE_SMB_V1)pContext; LWIO_LOCK_MUTEX(bInLock, &pNotifyState->mutex); if (pNotifyState->pAcb->AsyncCancelContext) { IoDereferenceAsyncCancelContext( &pNotifyState->pAcb->AsyncCancelContext); } pNotifyState->pAcb = NULL; LWIO_UNLOCK_MUTEX(bInLock, &pNotifyState->mutex); ntStatus = SrvNotifyBuildExecContext( pNotifyState, &pExecContext); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvProdConsEnqueue( gProtocolGlobals_SMB_V1.pWorkQueue, pExecContext); BAIL_ON_NT_STATUS(ntStatus); pExecContext = NULL; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pNotifyState->mutex); if (pNotifyState) { SrvNotifyStateRelease(pNotifyState); } if (pExecContext) { SrvReleaseExecContext(pExecContext); } return; error: LWIO_LOG_ERROR("Error: Failed processing change notify call back " "[status:0x%x]", ntStatus); // TODO: indicate error on file handle somehow goto cleanup; }
NTSTATUS IopFileObjectRundownEx( IN OUT PIO_FILE_OBJECT pFileObject, IN OPTIONAL PIO_ASYNC_COMPLETE_CALLBACK Callback, IN OPTIONAL PVOID CallbackContext, OUT PIO_STATUS_BLOCK IoStatusBlock ) { NTSTATUS status = STATUS_SUCCESS; int EE = 0; BOOLEAN isLocked = FALSE; IO_STATUS_BLOCK ioStatusBlock = { 0 }; IopFileObjectLock(pFileObject); isLocked = TRUE; if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CLOSE_DONE)) { LWIO_ASSERT(IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN)); // Note that there can be IRP references for completed IRPs sitting // around where the caller has not yet gotten rid of the IRP by // calling IoDereferenceAsyncCancelContext(). So we cannot assert // that (1 == pFileObject->ReferenceCount). Therefore, we do the // next best thing and check DispatchedIrpCount. Technically, if // someone got far enough into a new call that they created an IRP, // they will also have a new IRP file objeject reference. However, // the new IRP will fail to dispatch. While that is a logic bug // in the caller, we cannot trap those sorts of bugs via asserts // in the I/O manager. LWIO_ASSERT(0 == pFileObject->DispatchedIrpCount); IopFileObjectUnlock(pFileObject); isLocked = FALSE; IopFileObjectDereference(&pFileObject); status = STATUS_SUCCESS; GOTO_CLEANUP_EE(EE); } if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN)) { LWIO_LOG_ERROR("Attempt to rundown multiple times"); status = STATUS_FILE_CLOSED; GOTO_CLEANUP_EE(EE); } SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN); IopFileObjectUnlock(pFileObject); isLocked = FALSE; // Cancel everything now that rundown flag is set. IopIrpCancelFileObject(pFileObject, TRUE); // Now check whether we need to wait for rundown. IopFileObjectLock(pFileObject); isLocked = TRUE; if (0 != pFileObject->DispatchedIrpCount) { // Need to wait SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN_WAIT); if (!Callback) { // Wait inline for synchronous case LwRtlWaitConditionVariable( &pFileObject->Rundown.Condition, &pFileObject->Mutex, NULL); LWIO_ASSERT(0 == pFileObject->DispatchedIrpCount); } else { // Set up rundown callback for async case pFileObject->Rundown.Callback = Callback; pFileObject->Rundown.CallbackContext = CallbackContext; pFileObject->Rundown.pIoStatusBlock = IoStatusBlock; status = STATUS_PENDING; GOTO_CLEANUP_EE(EE); } } IopFileObjectUnlock(pFileObject); isLocked = FALSE; // We can now continue closing. status = IopContinueAsyncCloseFile( pFileObject, Callback, CallbackContext, IoStatusBlock); GOTO_CLEANUP_ON_STATUS_EE(status, EE); cleanup: if (isLocked) { IopFileObjectUnlock(pFileObject); } if (status && (STATUS_PENDING != status)) { ioStatusBlock.Status = status; } if ((STATUS_PENDING != status) && IoStatusBlock) { *IoStatusBlock = ioStatusBlock; } // TODO-Perhaps do not ASSERT here because LwRtlInitializeEvent() // could have failed if disaptching close IRP synchronously. LWIO_ASSERT((STATUS_SUCCESS == status) || (STATUS_PENDING == status) || (STATUS_FILE_CLOSED == status)); // TODO-Perhaps also remove object from device's file object // list such that it cannot be rundown multiple times. This // would avoid the STATUS_FILE_CLOSED above. IO_LOG_LEAVE_ON_STATUS_EE(status, EE); return status; }
static NTSTATUS RdrReadConfig( PRDR_CONFIG pConfig ) { NTSTATUS status = STATUS_SUCCESS; DWORD dwIdleTimeout = pConfig->usIdleTimeout; DWORD dwResponseTimeout = pConfig->usResponseTimeout; DWORD dwEchoTimeout = pConfig->usEchoTimeout; DWORD dwEchoInterval = pConfig->usEchoInterval; DWORD dwConnectTimeout = pConfig->usConnectTimeout; DWORD dwMinCreditReserve = pConfig->usMinCreditReserve; LWREG_CONFIG_ITEM configItems[] = { { "Smb2Enabled", TRUE, LwRegTypeBoolean, 0, MAXDWORD, NULL, &pConfig->bSmb2Enabled, NULL }, { "SigningEnabled", TRUE, LwRegTypeBoolean, 0, MAXDWORD, NULL, &pConfig->bSigningEnabled, NULL }, { "SigningRequired", TRUE, LwRegTypeBoolean, 0, MAXDWORD, NULL, &pConfig->bSigningRequired, NULL }, { "IdleTimeout", TRUE, LwRegTypeDword, 1, 300, NULL, &dwIdleTimeout, NULL }, { "ResponseTimeout", TRUE, LwRegTypeDword, 10, 900, NULL, &dwResponseTimeout, NULL }, { "EchoTimeout", TRUE, LwRegTypeDword, 5, 900, NULL, &dwEchoTimeout, NULL }, { "EchoInterval", TRUE, LwRegTypeDword, 30, 1800, NULL, &dwEchoInterval, NULL }, { "ConnectTimeout", TRUE, LwRegTypeDword, 5, 900, NULL, &dwConnectTimeout, NULL }, { "MinCreditReserve", TRUE, LwRegTypeDword, 1, 100, NULL, &dwMinCreditReserve, NULL }, }; status = NtRegProcessConfig( "Services\\lwio\\Parameters\\Drivers\\rdr", "Policy\\Services\\lwio\\Parameters\\Drivers\\rdr", configItems, sizeof(configItems)/sizeof(configItems[0])); if (status) { LWIO_LOG_ERROR("Failed to access device configuration [error code: %u]", status); status = STATUS_DEVICE_CONFIGURATION_ERROR; } BAIL_ON_NT_STATUS(status); pConfig->usIdleTimeout = (USHORT)dwIdleTimeout; pConfig->usResponseTimeout = (USHORT)dwResponseTimeout; pConfig->usEchoTimeout = (USHORT)dwEchoTimeout; pConfig->usEchoInterval = (USHORT)dwEchoInterval; pConfig->usConnectTimeout = (USHORT)dwConnectTimeout; pConfig->usMinCreditReserve = (USHORT)dwMinCreditReserve; cleanup: return status; error: goto cleanup; }