469 lines
13 KiB
C
469 lines
13 KiB
C
/*++
|
||
|
||
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;
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
BOOLEAN extendedInfo = FALSE;
|
||
SRV_NETWORK_OPEN_INFORMATION fileNetInfo;
|
||
ULONG flags;
|
||
USN usnValue;
|
||
ULONGLONG fileRefNumber;
|
||
#endif
|
||
|
||
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->UsingBlockingThread == 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 blocking thread.
|
||
//
|
||
SrvQueueWorkToBlockingThread( WorkContext );
|
||
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 ||
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
rfcb->WrittenTo ||
|
||
#endif
|
||
rfcb->AppendAccessGranted ) {
|
||
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
(VOID)SrvSetLastWriteTime(
|
||
rfcb,
|
||
SmbGetUlong( &request->LastWriteTimeInSeconds ),
|
||
rfcb->GrantedAccess,
|
||
TRUE
|
||
);
|
||
#else
|
||
(VOID)SrvSetLastWriteTime(
|
||
rfcb,
|
||
SmbGetUlong( &request->LastWriteTimeInSeconds ),
|
||
rfcb->GrantedAccess
|
||
);
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Now proceed to do the actual close file, even if there was
|
||
// a write behind error.
|
||
//
|
||
|
||
#ifdef SLMDBG
|
||
if ( SrvIsSlmStatus( &rfcb->Mfcb->FileName ) &&
|
||
(rfcb->GrantedAccess & FILE_WRITE_DATA) ) {
|
||
|
||
ULONG offset;
|
||
|
||
status = SrvValidateSlmStatus(
|
||
rfcb->Lfcb->FileHandle,
|
||
WorkContext,
|
||
&offset
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
SrvReportCorruptSlmStatus(
|
||
&rfcb->Mfcb->FileName,
|
||
status,
|
||
offset,
|
||
SLMDBG_CLOSE,
|
||
rfcb->Lfcb->Session
|
||
);
|
||
SrvReportSlmStatusOperations( rfcb, FALSE );
|
||
SrvDisallowSlmAccess(
|
||
&rfcb->Lfcb->FileObject->FileName,
|
||
rfcb->Lfcb->TreeConnect->Share->RootDirectoryHandle
|
||
);
|
||
SrvSetSmbError( WorkContext, STATUS_DISK_CORRUPT_ERROR );
|
||
}
|
||
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
if (request->WordCount == 5 && rfcb->ShareType == ShareTypeDisk) {
|
||
|
||
//
|
||
// This is an extended close request, fill in all the new fields
|
||
//
|
||
status = SrvQueryNetworkOpenInformation(
|
||
rfcb->Lfcb->FileHandle,
|
||
rfcb->Lfcb->FileObject,
|
||
&fileNetInfo,
|
||
FALSE
|
||
);
|
||
|
||
if ( NT_SUCCESS(status) ) {
|
||
|
||
PREQ_EXTENDED_CLOSE extendedRequest = (PREQ_EXTENDED_CLOSE) request;
|
||
LARGE_INTEGER ourUsnValue;
|
||
LARGE_INTEGER ourFileRefNumber;
|
||
BOOLEAN writeClose;
|
||
|
||
flags = SmbGetUlong( &extendedRequest->Flags );
|
||
|
||
extendedInfo = TRUE;
|
||
usnValue = 0;
|
||
fileRefNumber = 0;
|
||
|
||
if (rfcb->Lfcb->FileUpdated) {
|
||
|
||
//
|
||
// the file has been updated, let's close out the current
|
||
// usn journal entry so that we can get an accurate USN
|
||
// number (rather than have the entry generated at close).
|
||
//
|
||
|
||
rfcb->Lfcb->FileUpdated = FALSE;
|
||
|
||
writeClose = TRUE;
|
||
|
||
} else {
|
||
|
||
writeClose = FALSE;
|
||
}
|
||
|
||
//
|
||
// get the current USN number for this file.
|
||
//
|
||
|
||
status = SrvIssueQueryUsnInfoRequest( rfcb,
|
||
writeClose,
|
||
&ourUsnValue,
|
||
&ourFileRefNumber );
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
usnValue = ourUsnValue.QuadPart;
|
||
fileRefNumber = ourFileRefNumber.QuadPart;
|
||
} else {
|
||
IF_DEBUG(ERRORS) {
|
||
KdPrint(( "SrvSmbClose: Query USN info failed: 0x%X for handle %u\n",
|
||
status, rfcb->Lfcb->FileObject ));
|
||
}
|
||
}
|
||
} else {
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
KdPrint(( "SrvSmbClose: NtGetFileInfo returned 0x%lx\n", status ));
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
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.
|
||
//
|
||
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
if ( ! extendedInfo ) {
|
||
#endif
|
||
response->WordCount = 0;
|
||
SmbPutUshort( &response->ByteCount, 0 );
|
||
|
||
WorkContext->ResponseParameters = NEXT_LOCATION(
|
||
response,
|
||
RESP_CLOSE,
|
||
0
|
||
);
|
||
#ifdef INCLUDE_SMB_IFMODIFIED
|
||
} else {
|
||
|
||
PRESP_EXTENDED_CLOSE extendedResponse = (PRESP_EXTENDED_CLOSE) response;
|
||
LARGE_INTEGER usnToLarge;
|
||
|
||
extendedResponse->WordCount = SMB_RESP_EXTENDED_CLOSE_WORK_COUNT;
|
||
SmbPutUshort( &extendedResponse->ByteCount, 0 );
|
||
SmbPutUlong( &extendedResponse->Flags, flags );
|
||
|
||
SmbPutUlong(
|
||
&extendedResponse->CreationTime.HighPart,
|
||
fileNetInfo.CreationTime.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->CreationTime.LowPart,
|
||
fileNetInfo.CreationTime.LowPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->LastWriteTime.HighPart,
|
||
fileNetInfo.LastWriteTime.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->LastWriteTime.LowPart,
|
||
fileNetInfo.LastWriteTime.LowPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->ChangeTime.HighPart,
|
||
fileNetInfo.ChangeTime.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->ChangeTime.LowPart,
|
||
fileNetInfo.ChangeTime.LowPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->AllocationSize.HighPart,
|
||
fileNetInfo.AllocationSize.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->AllocationSize.LowPart,
|
||
fileNetInfo.AllocationSize.LowPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->EndOfFile.HighPart,
|
||
fileNetInfo.EndOfFile.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->EndOfFile.LowPart,
|
||
fileNetInfo.EndOfFile.LowPart
|
||
);
|
||
|
||
usnToLarge.QuadPart = usnValue;
|
||
|
||
SmbPutUlong(
|
||
&extendedResponse->UsnValue.HighPart,
|
||
usnToLarge.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->UsnValue.LowPart,
|
||
usnToLarge.LowPart
|
||
);
|
||
|
||
usnToLarge.QuadPart = fileRefNumber;
|
||
|
||
SmbPutUlong(
|
||
&extendedResponse->FileReferenceNumber.HighPart,
|
||
usnToLarge.HighPart
|
||
);
|
||
SmbPutUlong(
|
||
&extendedResponse->FileReferenceNumber.LowPart,
|
||
usnToLarge.LowPart
|
||
);
|
||
|
||
SmbPutUlong( &extendedResponse->FileAttributes, fileNetInfo.FileAttributes );
|
||
|
||
WorkContext->ResponseParameters = NEXT_LOCATION(
|
||
extendedResponse,
|
||
RESP_EXTENDED_CLOSE,
|
||
0
|
||
);
|
||
}
|
||
#endif
|
||
SmbStatus = SmbStatusSendResponse;
|
||
|
||
Cleanup:
|
||
SrvWmiEndContext(WorkContext);
|
||
return SmbStatus;
|
||
|
||
} // SrvSmbClose
|
||
|