You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
7.6 KiB
265 lines
7.6 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smbclose.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for processing the following SMBs:
|
|
|
|
Close
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 16-Nov-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "smbclose.tmh"
|
|
#pragma hdrstop
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvSmbClose )
|
|
#endif
|
|
|
|
SMB_PROCESSOR_RETURN_TYPE
|
|
SrvSmbClose (
|
|
SMB_PROCESSOR_PARAMETERS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes a Close SMB.
|
|
|
|
Arguments:
|
|
|
|
SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
|
|
of the parameters to SMB processor routines.
|
|
|
|
Return Value:
|
|
|
|
SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
|
|
|
|
--*/
|
|
|
|
{
|
|
PREQ_CLOSE request;
|
|
PRESP_CLOSE response;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PSESSION session;
|
|
PRFCB rfcb;
|
|
SMB_STATUS SmbStatus = SmbStatusInProgress;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
|
|
WorkContext->PreviousSMB = EVENT_TYPE_SMB_CLOSE;
|
|
SrvWmiStartContext(WorkContext);
|
|
|
|
IF_SMB_DEBUG(OPEN_CLOSE1) {
|
|
KdPrint(( "Close file request header at 0x%p, response header at 0x%p\n",
|
|
WorkContext->RequestHeader,
|
|
WorkContext->ResponseHeader ));
|
|
KdPrint(( "Close file request parameters at 0x%p, response parameters at 0x%p\n",
|
|
WorkContext->RequestParameters,
|
|
WorkContext->ResponseParameters ));
|
|
}
|
|
|
|
//
|
|
// Set up parameters.
|
|
//
|
|
|
|
request = (PREQ_CLOSE)(WorkContext->RequestParameters);
|
|
response = (PRESP_CLOSE)(WorkContext->ResponseParameters);
|
|
|
|
//
|
|
// If a session block has not already been assigned to the current
|
|
// work context, verify the UID. If verified, the address of the
|
|
// session block corresponding to this user is stored in the
|
|
// WorkContext block and the session block is referenced.
|
|
//
|
|
|
|
session = SrvVerifyUid(
|
|
WorkContext,
|
|
SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
|
|
);
|
|
|
|
if ( session == NULL ) {
|
|
|
|
IF_DEBUG(SMB_ERRORS) {
|
|
KdPrint(( "SrvSmbClose: Invalid UID: 0x%lx\n",
|
|
SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) ));
|
|
}
|
|
|
|
SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
|
|
SmbStatus = SmbStatusSendResponse;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// First, verify the FID. If verified, the RFCB and the TreeConnect
|
|
// block are referenced and their addresses are stored in the
|
|
// WorkContext block, and the RFCB address is returned.
|
|
//
|
|
// Call SrvVerifyFid, but do not fail (return NULL) if there
|
|
// is a saved write behind error for this rfcb. The rfcb is
|
|
// needed in order to process the close.
|
|
//
|
|
|
|
rfcb = SrvVerifyFid(
|
|
WorkContext,
|
|
SmbGetUshort( &request->Fid ),
|
|
FALSE,
|
|
SrvRestartSmbReceived, // serialize with raw write
|
|
&status
|
|
);
|
|
|
|
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
|
|
|
if ( !NT_SUCCESS( status ) ) {
|
|
|
|
//
|
|
// Invalid file ID. Reject the request.
|
|
//
|
|
|
|
IF_DEBUG(SMB_ERRORS) {
|
|
KdPrint(( "SrvSmbClose: Invalid FID: 0x%lx\n",
|
|
SmbGetUshort( &request->Fid ) ));
|
|
}
|
|
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
|
SmbStatus = SmbStatusSendResponse;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The work item has been queued because a raw write is in
|
|
// progress.
|
|
//
|
|
|
|
SmbStatus = SmbStatusInProgress;
|
|
goto Cleanup;
|
|
|
|
} else if( rfcb->ShareType == ShareTypePrint &&
|
|
WorkContext->UsingLpcThread == 0 ) {
|
|
|
|
//
|
|
// Closing this file will result in the scheduling of a print
|
|
// job. This means we will have to talk with srvsvc, a lengthy
|
|
// operation. Shift this close over to a LPC thread.
|
|
//
|
|
// NOTE: We don't allow the LPC throttle to reject this request
|
|
// because that would result in a failure to schedule a job.
|
|
//
|
|
SrvQueueWorkToLpcThread( WorkContext, FALSE );
|
|
SmbStatus = SmbStatusInProgress;
|
|
goto Cleanup;
|
|
|
|
} else if ( !NT_SUCCESS( rfcb->SavedError ) ) {
|
|
|
|
//
|
|
// Check the saved error.
|
|
//
|
|
|
|
(VOID) SrvCheckForSavedError( WorkContext, rfcb );
|
|
|
|
}
|
|
|
|
//
|
|
// Set the last write time on the file from the time specified in
|
|
// the SMB. Even though the SMB spec says that this is optional,
|
|
// we must support it for the following reasons:
|
|
//
|
|
// 1) The only way to set a file time in DOS is through a
|
|
// handle-based API which the DOS redir never sees; the API
|
|
// just sets the time in DOS's FCB, and the redir is expected
|
|
// set the time when it closes the file. Therefore, if we
|
|
// didn't do this, there would be no way t set a file time
|
|
// from DOS.
|
|
//
|
|
// 2) It is better for a file to have a redirector's version
|
|
// of a time than the server's. This keeps the time
|
|
// consistent for apps running on the client. Setting
|
|
// the file time on close keeps the file time consistent
|
|
// with the time on the client.
|
|
//
|
|
// !!! should we do anything with the return code from this routine?
|
|
|
|
if( rfcb->WriteAccessGranted ||
|
|
rfcb->AppendAccessGranted ) {
|
|
(VOID)SrvSetLastWriteTime(
|
|
rfcb,
|
|
SmbGetUlong( &request->LastWriteTimeInSeconds ),
|
|
rfcb->GrantedAccess
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now proceed to do the actual close file, even if there was
|
|
// a write behind error.
|
|
//
|
|
|
|
SrvCloseRfcb( rfcb );
|
|
|
|
//
|
|
// Dereference the RFCB immediately, rather than waiting for normal
|
|
// work context cleanup after the response send completes. This
|
|
// gets the xFCB structures cleaned up in a more timely manner.
|
|
//
|
|
// *** The specific motivation for this change was to fix a problem
|
|
// where a compatibility mode open was closed, the response was
|
|
// sent, and a Delete SMB was received before the send
|
|
// completion was processed. This resulted in the MFCB and LFCB
|
|
// still being present, which caused the delete processing to
|
|
// try to use the file handle in the LFCB, which we just closed
|
|
// here.
|
|
//
|
|
|
|
SrvDereferenceRfcb( rfcb );
|
|
WorkContext->Rfcb = NULL;
|
|
WorkContext->OplockOpen = FALSE;
|
|
|
|
#if 0
|
|
//
|
|
// If this is a CloseAndTreeDisc SMB, do the tree disconnect.
|
|
//
|
|
|
|
if ( WorkContext->RequestHeader->Command == SMB_COM_CLOSE_AND_TREE_DISC ) {
|
|
|
|
IF_SMB_DEBUG(OPEN_CLOSE1) {
|
|
KdPrint(( "Disconnecting tree 0x%lx\n", WorkContext->TreeConnect ));
|
|
}
|
|
|
|
SrvCloseTreeConnect( WorkContext->TreeConnect );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Build the response SMB.
|
|
//
|
|
response->WordCount = 0;
|
|
SmbPutUshort( &response->ByteCount, 0 );
|
|
|
|
WorkContext->ResponseParameters = NEXT_LOCATION(
|
|
response,
|
|
RESP_CLOSE,
|
|
0
|
|
);
|
|
|
|
SmbStatus = SmbStatusSendResponse;
|
|
|
|
Cleanup:
|
|
SrvWmiEndContext(WorkContext);
|
|
return SmbStatus;
|
|
|
|
} // SrvSmbClose
|
|
|