/*++ Copyright (c) 1991 Microsoft Corporation Module Name: smbnotfy.c Abstract: This module contains routine for processing the following SMBs: NT Notify Change. Author: Manny Weiser (mannyw) 29-Oct-1991 Revision History: --*/ #include "precomp.h" #include "smbnotfy.tmh" #pragma hdrstop // // Forward declarations // VOID SRVFASTCALL RestartNtNotifyChange ( PWORK_CONTEXT WorkContext ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, SrvSmbNtNotifyChange ) #pragma alloc_text( PAGE, RestartNtNotifyChange ) #pragma alloc_text( PAGE, SrvSmbFindNotify ) #pragma alloc_text( PAGE, SrvSmbFindNotifyClose ) #endif SMB_TRANS_STATUS SrvSmbNtNotifyChange ( IN OUT PWORK_CONTEXT WorkContext ) /*++ Routine Description: Processes an NT notify change SMB. This request arrives in an NT Transaction SMB. Arguments: WorkContext - Supplies the address of a Work Context Block describing the current request. See smbtypes.h for a more complete description of the valid fields. Return Value: BOOLEAN - Indicates whether an error occurred. See smbtypes.h for a more complete description. --*/ { PREQ_NOTIFY_CHANGE request; NTSTATUS status; PTRANSACTION transaction; PRFCB rfcb; USHORT fid; PAGED_CODE( ); transaction = WorkContext->Parameters.Transaction; request = (PREQ_NOTIFY_CHANGE)transaction->InSetup; if( transaction->SetupCount * sizeof( USHORT ) < sizeof( REQ_NOTIFY_CHANGE ) ) { SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER ); return SmbTransStatusErrorWithoutData; } fid = SmbGetUshort( &request->Fid ); // // Verify the FID. If verified, the RFCB block is referenced // and its addresses is stored in the WorkContext block, and the // RFCB address is returned. // rfcb = SrvVerifyFid( WorkContext, fid, TRUE, NULL, // don't serialize with raw write &status ); if ( rfcb == SRV_INVALID_RFCB_POINTER ) { // // Invalid file ID or write behind error. Reject the request. // IF_DEBUG(ERRORS) { KdPrint(( "SrvSmbNtIoctl: Status %X on FID: 0x%lx\n", status, fid )); } SrvSetSmbError( WorkContext, status ); return SmbTransStatusErrorWithoutData; } CHECK_FUNCTION_ACCESS( rfcb->GrantedAccess, IRP_MJ_DIRECTORY_CONTROL, IRP_MN_NOTIFY_CHANGE_DIRECTORY, 0, &status ); if ( !NT_SUCCESS( status ) ) { SrvStatistics.GrantedAccessErrors++; SrvSetSmbError( WorkContext, status ); return SmbTransStatusErrorWithoutData; } // // Set the Restart Routine addresses in the work context block. // WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel; WorkContext->FspRestartRoutine = RestartNtNotifyChange; // // Build the IRP to start a the I/O control. // Pass this request to the filesystem. // SrvBuildNotifyChangeRequest( WorkContext->Irp, rfcb->Lfcb->FileObject, WorkContext, SmbGetUlong( &request->CompletionFilter ), transaction->OutParameters, transaction->MaxParameterCount, request->WatchTree ); #if DBG_STUCK // // Since change notify can take an arbitrary amount of time, do // not include it in the "stuck detection & printout" code in the // scavenger // WorkContext->IsNotStuck = TRUE; #endif (VOID)IoCallDriver( IoGetRelatedDeviceObject( rfcb->Lfcb->FileObject ), WorkContext->Irp ); // // The call was successfully started, return InProgress to the caller // return SmbTransStatusInProgress; } VOID SRVFASTCALL RestartNtNotifyChange ( PWORK_CONTEXT WorkContext ) /*++ Routine Description: Completes processing of an NT Notify Change SMB. Arguments: WorkContext - Work context block for the operation. Return Value: None. --*/ { NTSTATUS status; PTRANSACTION transaction; PIRP irp; ULONG length; PAGED_CODE( ); // // If we built an MDL for this IRP, free it now. // irp = WorkContext->Irp; if ( irp->MdlAddress != NULL ) { MmUnlockPages( irp->MdlAddress ); IoFreeMdl( irp->MdlAddress ); irp->MdlAddress = NULL; } status = irp->IoStatus.Status; if ( !NT_SUCCESS( status ) ) { SrvSetSmbError( WorkContext, status ); SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusErrorWithoutData ); return; } // // The Notify change request has completed successfully. Send the // response. // length = (ULONG)irp->IoStatus.Information; transaction = WorkContext->Parameters.Transaction; ASSERT( length <= transaction->MaxParameterCount ); if ( irp->UserBuffer != NULL ) { // // The file system wanted "neither" I/O for this request. This // means that the file system will have allocated a system // buffer for the returned data. Normally this would be copied // back to our user buffer during I/O completion, but we // short-circuit I/O completion before the copy happens. So we // have to copy the data ourselves. // if ( irp->AssociatedIrp.SystemBuffer != NULL ) { ASSERT( irp->UserBuffer == transaction->OutParameters ); RtlCopyMemory( irp->UserBuffer, irp->AssociatedIrp.SystemBuffer, length ); } } transaction->SetupCount = 0; transaction->ParameterCount = length; transaction->DataCount = 0; // // !!! Mask a base notify bug, remove when the bug is fixed. // if ( status == STATUS_NOTIFY_CLEANUP ) { transaction->ParameterCount = 0; } SrvCompleteExecuteTransaction( WorkContext, SmbTransStatusSuccess ); return; } // RestartNtNotifyChange // // Since OS/2 chose not to expose the DosFindNotifyFirst/Next/Close APIs, // OS/2 LAN Man does not officially support these SMBs. This is true, // even though the Find Notify SMB is documented as a LAN Man 2.0 SMB // there is code in both the LM2.0 server and redir to support it. // // Therefore the NT server will also not support these SMBs. // SMB_TRANS_STATUS SrvSmbFindNotify ( IN OUT PWORK_CONTEXT WorkContext ) { PAGED_CODE( ); return SrvTransactionNotImplemented( WorkContext ); } SMB_PROCESSOR_RETURN_TYPE SrvSmbFindNotifyClose ( SMB_PROCESSOR_PARAMETERS ) { PAGED_CODE( ); return SrvSmbNotImplemented( SMB_PROCESSOR_ARGUMENTS ); }