|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
DownLvlO.c
Abstract:
This module implements downlevel opens.
Author:
Joe Linn [JoeLi] 7-March-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
////
//// The Bug check file id for this module
////
//
//#define BugCheckFileId (RDBSS_BUG_CHECK_LOCAL_CREATE)
//
// The debug trace level
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxSmbGetFileAttributes)
#pragma alloc_text(PAGE, MRxSmbCoreDeleteForSupercedeOrClose)
#pragma alloc_text(PAGE, MRxSmbCoreCheckPath)
#pragma alloc_text(PAGE, MRxSmbCoreOpen)
#pragma alloc_text(PAGE, MRxSmbSetFileAttributes)
#pragma alloc_text(PAGE, MRxSmbCoreCreateDirectory)
#pragma alloc_text(PAGE, MRxSmbCoreCreate)
#pragma alloc_text(PAGE, MRxSmbCloseAfterCoreCreate)
#pragma alloc_text(PAGE, MRxSmbCoreTruncate)
#pragma alloc_text(PAGE, MRxSmbDownlevelCreate)
#pragma alloc_text(PAGE, MRxSmbFinishGFA)
#pragma alloc_text(PAGE, MRxSmbFinishCoreCreate)
#pragma alloc_text(PAGE, MRxSmbPopulateFileInfoInOE)
#pragma alloc_text(PAGE, MRxSmbFinishCoreOpen)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromCoreCreateDirectory)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromFakeGFAResponse)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromGFAResponse)
#pragma alloc_text(PAGE, MRxSmbConvertSmbTimeToTime)
#pragma alloc_text(PAGE, MRxSmbConvertTimeToSmbTime)
#pragma alloc_text(PAGE, MRxSmbTimeToSecondsSince1970)
#pragma alloc_text(PAGE, MRxSmbSecondsSince1970ToTime)
#pragma alloc_text(PAGE, MRxSmbMapSmbAttributes)
#pragma alloc_text(PAGE, MRxSmbMapDisposition)
#pragma alloc_text(PAGE, MRxSmbUnmapDisposition)
#pragma alloc_text(PAGE, MRxSmbMapDesiredAccess)
#pragma alloc_text(PAGE, MRxSmbMapShareAccess)
#pragma alloc_text(PAGE, MRxSmbMapFileAttributes)
#endif
#define Dbg (DEBUG_TRACE_CREATE)
#pragma warning(error:4101) // Unreferenced local variable
VOID MRxSmbPopulateFileInfoInOE( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, USHORT FileAttributes, ULONG LastWriteTimeInSeconds, ULONG FileSize );
PVOID MRxSmbPopulateFcbInitPacketForCore(void);
NTSTATUS MRxSmbPseudoOpenTailFromGFAResponse ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange ); NTSTATUS MRxSmbPseudoOpenTailFromFakeGFAResponse ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, RX_FILE_TYPE StorageType ); NTSTATUS MRxSmbPseudoOpenTailFromCoreCreateDirectory ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, USHORT Attributes );
//CODE.IMPROVEMENT all of these routines that do a single core operation are to
// be rolled up into a single routine......
// for this reason, we shouldn't worry about the commonality...the more the better!
NTSTATUS MRxSmbGetFileAttributes( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE ) /*++
Routine Description:
This routine does a GetFileAttributes and remembers the reponse. This routine also does the cache for the file information.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status;
RxCaptureFcb; RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = NULL; PMRX_SMB_SRV_OPEN smbSrvOpen = NULL;
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange; PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(Exchange);
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbSynchronousGetFileAttributes entering.......OE=%08lx\n",OrdinaryExchange));
if (FsRtlDoesNameContainWildCards(RemainingName)) { Status = RX_MAP_STATUS(OBJECT_NAME_INVALID); goto FINALLY; }
if (MRxSmbIsFileNotFoundCached(RxContext)) { Status = STATUS_OBJECT_NAME_NOT_FOUND; goto FINALLY; }
// Try to find the cached file infomation
if (MRxSmbIsFileInfoCacheFound(RxContext, &OrdinaryExchange->Create.FileInfo, &Status, NULL)){ goto FINALLY; }
// If the file has already been opened a QUERY_INFORMATION2 can be issued while
// QUERY_INFORMATION can only be issued against pseudo opened and not yet
// opened files.
if (capFobx != NULL) { SrvOpen = capFobx->pSrvOpen; if (SrvOpen != NULL) smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); }
StufferState = &OrdinaryExchange->AssociatedStufferState;
if (pServerEntry->Server.Dialect > PCNET1_DIALECT && (smbSrvOpen != NULL) && (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) && !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN) && (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE))) { COVERED_CALL( MRxSmbStartSMBCommand( StufferState, SetInitialSMB_ForReuse, SMB_COM_QUERY_INFORMATION2, SMB_REQUEST_SIZE(QUERY_INFORMATION2), NO_EXTRA_DATA, SMB_BEST_ALIGNMENT(1,0), RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ GFA before stuffing",StufferState);
MRxSmbStuffSMB ( StufferState, "0wB!", // 0 UCHAR WordCount;
smbSrvOpen->Fid, // w _USHORT(Fid);
SMB_WCT_CHECK(1) 0 // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
);
MRxSmbDumpStufferState (700,"SMB w/ GFA after stuffing",StufferState); } else { COVERED_CALL( MRxSmbStartSMBCommand( StufferState, SetInitialSMB_ForReuse, SMB_COM_QUERY_INFORMATION, SMB_REQUEST_SIZE(QUERY_INFORMATION), NO_EXTRA_DATA, SMB_BEST_ALIGNMENT(1,0), RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ GFA before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB ( StufferState, "0B4!", // 0 UCHAR WordCount; // Count of parameter words = 0
SMB_WCT_CHECK(0) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
RemainingName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ GFA after stuffing",StufferState); }
Status = SmbPseOrdinaryExchange( SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_GFA );
if (NT_SUCCESS(Status)) { MRxSmbCreateFileInfoCache(RxContext, &OrdinaryExchange->Create.FileInfo, pServerEntry, Status); } else { if (Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND) { // create the name based file not found cache
MRxSmbCacheFileNotFound(RxContext); } else { // invalid the name based file not found cache if other error happens
MRxSmbInvalidateFileNotFoundCache(RxContext); } }
FINALLY:
if (NT_SUCCESS(Status)) { OrdinaryExchange->Create.StorageTypeFromGFA = OrdinaryExchange->Create.FileInfo.Standard.Directory ? FileTypeDirectory : FileTypeFile; }
RxDbgTrace(-1, Dbg, ("MRxSmbSynchronousGetFileAttributes exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCoreDeleteForSupercedeOrClose( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE, BOOLEAN DeleteDirectory ) /*++
Routine Description:
This routine does a GetFileAttributes and remembers the reponse.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; RxCaptureFcb; RxCaptureFobx;
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreDeleteForSupercede entering.......OE=%08lx\n",OrdinaryExchange));
StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState ); ASSERT( OrdinaryExchange->pPathArgument1 != NULL );
//
if (!DeleteDirectory) { ULONG SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN; // a la rdr1
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_DELETE, SMB_REQUEST_SIZE(DELETE), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ del before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since it's in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
// on the other hand, if it's NT<-->NT we don't do it here anyway
MRxSmbStuffSMB (StufferState, "0wB4!", // 0 UCHAR WordCount; // Count of parameter words = 1
SearchAttributes, // w _USHORT( SearchAttributes );
SMB_WCT_CHECK(1) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
OrdinaryExchange->pPathArgument1 // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
); } else {
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_DELETE_DIRECTORY, SMB_REQUEST_SIZE(DELETE_DIRECTORY), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ rmdir before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB (StufferState, "0B4!", // 0 UCHAR WordCount; // Count of parameter words = 0
SMB_WCT_CHECK(0) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
OrdinaryExchange->pPathArgument1 // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
); }
MRxSmbDumpStufferState (700,"SMB w/ del/rmdir after stuffing",StufferState);
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE );
if (Status == STATUS_SUCCESS) { // invalid the name based file info cache
MRxSmbInvalidateFileInfoCache(RxContext); // Trounce FullDir Cache, since a file has been deleted.
MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
MRxSmbInvalidateInternalFileInfoCache(RxContext); MRxSmbCacheFileNotFound(RxContext);
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED); } else { RxLog(("Delete File: %x %wZ\n",Status,OrdinaryExchange->pPathArgument1)); SmbLog(LOG, MRxSmbCoreDeleteForSupercedeOrClose, LOGULONG(Status) LOGUSTR(*OrdinaryExchange->pPathArgument1)); }
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreDeleteForSupercede exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCoreCheckPath( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE ) /*++
Routine Description:
This routine does a GetFileAttributes and remembers the reponse.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; FILE_BASIC_INFORMATION FileInfoBasic;
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreCheckPath entering.......OE=%08lx\n", OrdinaryExchange)); // Try to find the cached file infomation
if (MRxSmbIsBasicFileInfoCacheFound(RxContext, &FileInfoBasic, &Status, OrdinaryExchange->pPathArgument1)){
if (Status == STATUS_SUCCESS) { if (!(FileInfoBasic.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { Status = STATUS_NOT_A_DIRECTORY; }
goto FINALLY; } } StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_CHECK_DIRECTORY, SMB_REQUEST_SIZE(CHECK_DIRECTORY), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0), RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ chkdir before stuffing",StufferState);
//CODE.IMPROVEMENT many of these single argument guys can be rooled up
MRxSmbStuffSMB (StufferState, "0B4!", // UCHAR WordCount; // Count of parameter words = 0
SMB_WCT_CHECK(0) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
OrdinaryExchange->pPathArgument1 // 4 UCHAR BufferFormat; // 0x04 -- ASCII
// UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ chkdir after stuffing",StufferState);
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_CORECHECKDIRECTORY );
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreCheckPath exiting.......OE=%08lx, st=%08lx\n", OrdinaryExchange,Status) ); return(Status); }
NTSTATUS MRxSmbCoreOpen( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE, ULONG OpenShareMode, ULONG Attribute ) /*++
Routine Description:
This routine does a core open.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; //RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange; PSMBCE_SERVER pServer = SmbCeGetExchangeServer(Exchange);
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreOpen entering.......OE=%08lx\n",OrdinaryExchange));
StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState ); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_OPEN, SMB_REQUEST_SIZE(OPEN), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ coreopen before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB (StufferState, "0wwB4!", // 0 UCHAR WordCount; // Count of parameter words = 2
OpenShareMode, // w _USHORT( DesiredAccess ); // Mode - read/write/share
Attribute, // w _USHORT( SearchAttributes );
SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
RemainingName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ coreopen after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_COREOPEN );
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreOpen exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbSetFileAttributes( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE, ULONG SmbAttributes ) /*++
Routine Description:
This routine does a core create directory.....
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; RxCaptureFobx; PMRX_SRV_OPEN SrvOpen = NULL; PMRX_SMB_SRV_OPEN smbSrvOpen = NULL; PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
ULONG LastWriteTime = 0; ULONG FileAttributes = 0; PLARGE_INTEGER pCreationTime = NULL; PLARGE_INTEGER pLastWriteTime = NULL; PLARGE_INTEGER pLastAccessTime = NULL; SMB_TIME SmbCreationTime; SMB_DATE SmbCreationDate; SMB_TIME SmbLastWriteTime; SMB_DATE SmbLastWriteDate; SMB_TIME SmbLastAccessTime; SMB_DATE SmbLastAccessDate; PSMBSTUFFER_BUFFER_STATE StufferState; BOOLEAN TimeSpecified = FALSE; PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbSetFileAttributes entering.......OE=%08lx\n",OrdinaryExchange)); StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState );
if (capFobx != NULL) { SrvOpen = capFobx->pSrvOpen; if (SrvOpen != NULL) smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); }
SmbCreationTime.Ushort = 0; SmbCreationDate.Ushort = 0; SmbLastWriteTime.Ushort = 0; SmbLastWriteDate.Ushort = 0; SmbLastAccessTime.Ushort = 0; SmbLastAccessDate.Ushort = 0;
if (RxContext->MajorFunction == IRP_MJ_SET_INFORMATION) { BOOLEAN GoodTime; FileAttributes = ((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->FileAttributes; pCreationTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->CreationTime; pLastWriteTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->LastWriteTime; pLastAccessTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->LastAccessTime;
if (pLastWriteTime->QuadPart != 0) { GoodTime = MRxSmbTimeToSecondsSince1970( pLastWriteTime, SmbCeGetExchangeServer(OrdinaryExchange), &LastWriteTime);
if (!GoodTime) { Status = STATUS_INVALID_PARAMETER; goto FINALLY; }
GoodTime = MRxSmbConvertTimeToSmbTime(pLastWriteTime, (PSMB_EXCHANGE)OrdinaryExchange, &SmbLastWriteTime, &SmbLastWriteDate); if (!GoodTime) { Status = STATUS_INVALID_PARAMETER; goto FINALLY; } TimeSpecified = TRUE; } if (pLastAccessTime->QuadPart != 0) { GoodTime = MRxSmbConvertTimeToSmbTime(pLastAccessTime, (PSMB_EXCHANGE)OrdinaryExchange, &SmbLastAccessTime, &SmbLastAccessDate); if (!GoodTime) { Status = STATUS_INVALID_PARAMETER; goto FINALLY; } TimeSpecified = TRUE; } if (pCreationTime->QuadPart != 0) { GoodTime = MRxSmbConvertTimeToSmbTime(pCreationTime, (PSMB_EXCHANGE)OrdinaryExchange, &SmbCreationTime, &SmbCreationDate); if (!GoodTime) { Status = STATUS_INVALID_PARAMETER; goto FINALLY; } TimeSpecified = TRUE; }
if (!TimeSpecified && (FileAttributes == 0)) { // caller didn't specify anything worth doing. Return success
// 442486
Status = STATUS_SUCCESS; goto FINALLY; } }
if (smbSrvOpen == NULL || FileAttributes != 0 || RxContext->MajorFunction != IRP_MJ_SET_INFORMATION || FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN) || FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) || (pLastWriteTime->QuadPart == 0 && pLastAccessTime->QuadPart == 0 && pCreationTime->QuadPart == 0)) { COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_SET_INFORMATION, SMB_REQUEST_SIZE(SET_INFORMATION), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')));
MRxSmbDumpStufferState (1100,"SMB w/ sfa before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB (StufferState, "0wdwwwwwB4!", // 0 UCHAR WordCount; // Count of parameter words = 8
SmbAttributes, // w _USHORT( FileAttributes );
LastWriteTime, // d _ULONG( LastWriteTimeInSeconds );
0,0,0,0,0, // 5*w _USHORT( Reserved )[5]; // Reserved (must be 0)
SMB_WCT_CHECK(8) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
RemainingName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ sfa after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_SFA); } else { COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_SET_INFORMATION2, SMB_REQUEST_SIZE(SET_INFORMATION2), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')));
MRxSmbDumpStufferState (1100,"SMB w/ sfa 2 before stuffing",StufferState);
MRxSmbStuffSMB (StufferState, "0wwwwwwwB!", // 0 UCHAR WordCount; // Count of parameter words = 8
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
SmbCreationDate.Ushort, // w SMB_TIME CreationDate;
SmbCreationTime.Ushort, // w SMB_TIME CreationTime;
SmbLastAccessDate.Ushort, // w SMB_TIME LastAccessDate;
SmbLastAccessTime.Ushort, // w SMB_TIME LastAccessTime;
SmbLastWriteDate.Ushort, // w SMB_TIME LastWriteDate;
SmbLastWriteTime.Ushort, // w SMB_TIME LastWriteTime;
SMB_WCT_CHECK(7) 0 // _USHORT( ByteCount ); // Count of data bytes; min = 0
// UCHAR Buffer[1]; // Reserved buffer
);
MRxSmbDumpStufferState (700,"SMB w/ sfa 2 after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_SFA2); }
if (Status == STATUS_SUCCESS) { if (RxContext->MajorFunction != IRP_MJ_SET_INFORMATION) { FileAttributes = MRxSmbMapSmbAttributes((USHORT)SmbAttributes); }
MRxSmbUpdateBasicFileInfoCache(RxContext, FileAttributes, pLastWriteTime);
MRxSmbUpdateStandardFileInfoCache(RxContext, NULL, (BOOLEAN)(FileAttributes & FILE_ATTRIBUTE_DIRECTORY));
MRxSmbInvalidateFileNotFoundCache(RxContext); MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
} else { if (Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND) { // create the name based file not found cache
MRxSmbCacheFileNotFound(RxContext); } else { // invalid the name based file not found cache if other error happens
MRxSmbInvalidateFileNotFoundCache(RxContext); }
// invalid the name based file info cache
MRxSmbInvalidateFileInfoCache(RxContext); // Don't have to touch FullDir Cache, since we encountered Error.
}
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbSFAAfterCreateDirectory exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCoreCreateDirectory( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE ) /*++
Routine Description:
This routine does a core create directory.....
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; RxCaptureFcb; //RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreCreateDirectory entering.......OE=%08lx\n",OrdinaryExchange)); StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState ); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse, SMB_COM_CREATE_DIRECTORY, SMB_REQUEST_SIZE(CREATE_DIRECTORY), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ corecreatedir before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB (StufferState, "0B4!", // 0 UCHAR WordCount; // Count of parameter words = 0
SMB_WCT_CHECK(0) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
RemainingName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ corecreatedir after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_CORECREATEDIRECTORY );
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreCreateDirectory exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCoreCreate( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE, ULONG Attribute, BOOLEAN CreateNew ) /*++
Routine Description:
This routine does a core create.....if the flag is set we use create new.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; RxCaptureFcb; //RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreCreate entering.......OE=%08lx\n",OrdinaryExchange)); StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState ); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse, (UCHAR)(CreateNew?SMB_COM_CREATE_NEW:SMB_COM_CREATE), SMB_REQUEST_SIZE(CREATE), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ coreopen before stuffing",StufferState);
//CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
// otherwise, we don't need to copy the name here, we can just Mdl like in writes
MRxSmbStuffSMB (StufferState, "0wdB4!", // 0 UCHAR WordCount; // Count of parameter words = 3
Attribute, // w _USHORT( FileAttributes ); // New file attributes
0, // d _ULONG( CreationTimeInSeconds ); // Creation time
SMB_WCT_CHECK(3) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
RemainingName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR FileName[]; // File name
);
MRxSmbDumpStufferState (700,"SMB w/ corecreate after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_CORECREATE );
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCloseAfterCoreCreate( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE ) /*++
Routine Description:
This routine does a close.....
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; RxCaptureFcb; RxCaptureFobx;
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCloseAfterCoreCreate entering.......OE=%08lx\n",OrdinaryExchange)); StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse, SMB_COM_CLOSE, SMB_REQUEST_SIZE(CLOSE), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
MRxSmbDumpStufferState (1100,"SMB w/ closeaftercorecreate before stuffing",StufferState);
MRxSmbStuffSMB (StufferState, "0wdB!", // 0 UCHAR WordCount; // Count of parameter words = 3
// w _USHORT( Fid ); // File handle
OrdinaryExchange->Create.FidReturnedFromCreate, 0, // d _ULONG( LastWriteTimeInSeconds ); // Time of last write, low and high
SMB_WCT_CHECK(3) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
// UCHAR Buffer[1]; // empty
);
MRxSmbDumpStufferState (700,"SMB w/ closeaftercorecreate after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_CLOSEAFTERCORECREATE );
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCloseAfterCoreCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbCoreTruncate( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE, ULONG Fid, ULONG FileTruncationPoint ) /*++
Routine Description:
This routine does a truncate to implement FILE_OVERWRITE and FILE_OVERWRITE_IF..... it is also used in the "extend-for-cached-write" path.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/ { NTSTATUS Status; RxCaptureFcb; RxCaptureFobx;
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCoreTruncate entering.......OE=%08lx\n",OrdinaryExchange)); StufferState = &OrdinaryExchange->AssociatedStufferState;
ASSERT( StufferState );
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse, SMB_COM_WRITE, SMB_REQUEST_SIZE(WRITE), NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED, 0,0,0,0 STUFFERTRACE(Dbg,'FC')) )
MRxSmbDumpStufferState (1100,"SMB w/ coretruncate before stuffing",StufferState);
MRxSmbStuffSMB (StufferState, "0wwdwByw!", // 0 UCHAR WordCount; // Count of parameter words = 5
Fid, // w _USHORT( Fid ); // File handle
0, // w _USHORT( Count ); // Number of bytes to be written
FileTruncationPoint, // d _ULONG( Offset ); // Offset in file to begin write
0, // w _USHORT( Remaining ); // Bytes remaining to satisfy request
SMB_WCT_CHECK(5) // B _USHORT( ByteCount ); // Count of data bytes
// //UCHAR Buffer[1]; // Buffer containing:
0x01, // y UCHAR BufferFormat; // 0x01 -- Data block
0 // w _USHORT( DataLength ); // Length of data
// ULONG Buffer[1]; // Data
);
MRxSmbDumpStufferState (700,"SMB w/ coretruncate after stuffing",StufferState); //ASSERT(!"Now it's stuffed");
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, SMBPSE_OETYPE_CORETRUNCATE );
if (Status == STATUS_SUCCESS) { LARGE_INTEGER FileSize;
FileSize.HighPart = 0; FileSize.LowPart = FileTruncationPoint;
MRxSmbUpdateFileInfoCacheFileSize(RxContext, &FileSize); } else { if (Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND) { // create the name based file not found cache
MRxSmbCacheFileNotFound(RxContext); } else { // invalid the name based file not found cache if other error happens
MRxSmbInvalidateFileNotFoundCache(RxContext);
}
// invalid the name based file info cache
MRxSmbInvalidateFileInfoCache(RxContext);
// Don't have to touch FullDir Cache, since Error was encountered
}
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbCoreTruncate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbDownlevelCreate( SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE ) /*++
Routine Description:
This routine implements downlevel creates.
Arguments:
OrdinaryExchange - an exchange to be used for conducting this open.
Return Value:
RXSTATUS - The return status for the operation
Notes:
For core, in particular, this is pretty painful because a different smb must be used for different dispositions. In addition, we cannot really open a directory.
By in large, we will follow a strategy similar to rdr1. If the openmode maps into something that a downlevel server won't understand then we don't really open the file.....we just do a GFA to ensure that it's there and hope that we can do path-based ops for the duration.
--*/ { NTSTATUS Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
RxCaptureFcb; //RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); PUNICODE_STRING PathName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb); PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
ULONG CreateOptions = cp->CreateOptions; ULONG FileAttributes = cp->FileAttributes; ACCESS_MASK DesiredAccess = cp->DesiredAccess; USHORT ShareAccess = (USHORT)(cp->ShareAccess); ULONG Disposition = cp->Disposition;
USHORT mappedDisposition = MRxSmbMapDisposition(Disposition); USHORT mappedSharingMode = MRxSmbMapShareAccess(ShareAccess); USHORT mappedAttributes = MRxSmbMapFileAttributes(FileAttributes); USHORT mappedOpenMode = MRxSmbMapDesiredAccess(DesiredAccess);
LARGE_INTEGER AllocationSize = cp->AllocationSize;
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange; PSMBCE_SERVER pServer = SmbCeGetExchangeServer(Exchange);
PSMBSTUFFER_BUFFER_STATE StufferState;
BOOLEAN MustBeAFile = (MustBeFile(CreateOptions)!=0); BOOLEAN MustBeADirectory = (MustBeDirectory(CreateOptions)!=0) || BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH); BOOLEAN ItsADirectory = FALSE; BOOLEAN ItsTheShareRoot = FALSE;
PAGED_CODE(); // Down level protocols don't have the execute mode.
if (mappedOpenMode == (USHORT)SMB_DA_ACCESS_EXECUTE) mappedOpenMode = (USHORT)SMB_DA_ACCESS_READ;
RxDbgTrace(+1, Dbg, ("MRxSmbDownlevelCreate entering.......OE=%08lx\n",OrdinaryExchange)); RxDbgTrace( 0, Dbg, ("mapAtt,Shr,Disp,OM %04lx,%04lx,%04lx,%04lx\n", mappedAttributes,mappedSharingMode,mappedDisposition,mappedOpenMode));
SmbPseOEAssertConsistentLinkageFromOE("Downlevel Create:");
StufferState = &OrdinaryExchange->AssociatedStufferState;
if (OrdinaryExchange->Create.CreateWithEasSidsOrLongName) { Status = RX_MAP_STATUS(NOT_SUPPORTED); goto FINALLY; }
if (AllocationSize.HighPart != 0) { //CODE.IMPROVEMENT why is the above a not-supported while this is a invalid-param??? joejoe
Status = RX_MAP_STATUS(INVALID_PARAMETER); goto FINALLY; }
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); OrdinaryExchange->Create.smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); OrdinaryExchange->pPathArgument1 = PathName;
//
// we know that the root a share exists and that it's a directory....the catch is that GetFileAttributes
// will return a NO_SUCH_FILE error for the root if it's really a root on the server. record this and use it
// to our advantage later.
if ((PathName->Length == 0) || ((PathName->Length == sizeof(WCHAR)) && (PathName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) ) { //if must be a file, it's an error.........
if (MustBeAFile) { Status = RX_MAP_STATUS(FILE_IS_A_DIRECTORY); goto FINALLY; }
//
//if it's the right kind of open, i can just finish up now. these opens are common for GetFSInfo
if ((Disposition == FILE_OPEN) || (Disposition == FILE_OPEN_IF)) { Status = MRxSmbPseudoOpenTailFromFakeGFAResponse ( OrdinaryExchange, FileTypeDirectory ); goto FINALLY; } MustBeADirectory = TRUE; // we know it's a directory!
ItsTheShareRoot = TRUE; }
//// if all the user wants is attributes and it's a FILE_OPEN, don't do the open now....
//// rather, we'll send pathbased ops later (or do a deferred open if necessary)...
if (Disposition == FILE_OPEN && (MustBeADirectory || !(cp->DesiredAccess & ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES)))) { Status = MRxSmbPseudoOpenTailFromFakeGFAResponse(OrdinaryExchange, MustBeADirectory?FileTypeDirectory:FileTypeFile); if (Status == STATUS_SUCCESS) { Status = MRxSmbQueryFileInformationFromPseudoOpen( SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, FileBasicInformation);
if (Status == STATUS_SUCCESS) { if (MustBeADirectory && !OrdinaryExchange->Create.FileInfo.Standard.Directory) { Status = STATUS_NOT_A_DIRECTORY; }
if (MustBeAFile && OrdinaryExchange->Create.FileInfo.Standard.Directory) { Status = STATUS_FILE_IS_A_DIRECTORY; } }
if (Status != STATUS_SUCCESS) { RxFreePool(smbSrvOpen->DeferredOpenContext); smbSrvOpen->DeferredOpenContext = NULL; } }
goto FINALLY; }
if ( (mappedOpenMode == ((USHORT)-1)) || (Disposition == FILE_SUPERSEDE) || (!MustBeAFile) ) {
//
// go find out what's there.......
Status = MRxSmbGetFileAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
if (Status == STATUS_SUCCESS && MustBeADirectory && !OrdinaryExchange->Create.FileInfo.Standard.Directory) { Status = STATUS_NOT_A_DIRECTORY; goto FINALLY; } RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate GFAorCPstatus=%08lx\n",Status));
if (NT_SUCCESS(Status)) { ULONG Attributes = SmbGetUshort(&OrdinaryExchange->Create.FileInfo.Basic.FileAttributes); ItsADirectory = BooleanFlagOn(Attributes,SMB_FILE_ATTRIBUTE_DIRECTORY); RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate attributes=%08lx\n",Attributes)); if ((Disposition==FILE_CREATE)) { Status = STATUS_OBJECT_NAME_COLLISION; goto FINALLY; } if (MustBeADirectory && !ItsADirectory && (Disposition!=FILE_SUPERSEDE)) { if (Disposition == FILE_OPEN) { // This fix is required for the DFS driver which seems to handle
// STATUS_OBJECT_TYPE_MISMATCH in a special way.
// DFS should be fixed.
Status = STATUS_OBJECT_NAME_COLLISION; } else { Status = STATUS_OBJECT_TYPE_MISMATCH; } goto FINALLY; } if (MustBeAFile && ItsADirectory && (Disposition!=FILE_SUPERSEDE)) { if (Disposition == FILE_OPEN) { // This fix is required for the DFS driver which seems to handle
// STATUS_OBJECT_TYPE_MISMATCH in a special way.
// DFS should be fixed.
Status = STATUS_FILE_IS_A_DIRECTORY; } else { Status = STATUS_OBJECT_TYPE_MISMATCH; } goto FINALLY; } //if (!MustBeAFile && ItsADirectory && (Disposition==FILE_OPEN)){
if (Disposition==FILE_OPEN || Disposition==FILE_OPEN_IF){ //we're done except to finish AND to set the flags in the srvopen
MRxSmbPseudoOpenTailFromGFAResponse ( OrdinaryExchange ); goto FINALLY; } } else if ( (Status!=STATUS_NO_SUCH_FILE) && (Status!=STATUS_OBJECT_PATH_NOT_FOUND) ) { goto FINALLY; } else if ((Disposition==FILE_CREATE) || (Disposition==FILE_OPEN_IF) || (Disposition==FILE_OVERWRITE_IF) || (Disposition==FILE_SUPERSEDE)) { //CODE.IMPROVEMENT doing this with four compares is ineficient; we should have a
// table or something
NOTHING; } else if (ItsTheShareRoot) { PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); //here we have run into a true root....so we can't get attributes. fill in a fake
//response and finish. also, flip the bit that says we can't gfa this guy.
Status = MRxSmbPseudoOpenTailFromFakeGFAResponse ( OrdinaryExchange, FileTypeDirectory ); smbSrvOpen->Flags |= SMB_SRVOPEN_FLAG_CANT_GETATTRIBS; goto FINALLY; } else { goto FINALLY; } }
SmbCeResetExchange(&OrdinaryExchange->Exchange); //must reset!
if (NT_SUCCESS(Status) &&(Disposition == FILE_SUPERSEDE)) { //
//we have to get rid of the existing entity...using a delete or a rmdir as appropriate
Status = MRxSmbCoreDeleteForSupercedeOrClose(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, OrdinaryExchange->Create.FileInfo.Standard.Directory ); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate could notsupersede st=%08lx\n",Status)); goto FINALLY; } SmbCeResetExchange(&OrdinaryExchange->Exchange); //must reset!
//CODE.IMPROVEMENT there should be some way
//that is more automatic than this
}
if (MustBeADirectory || (ItsADirectory &&(Disposition == FILE_SUPERSEDE)) ) {
ASSERT (Disposition!=FILE_OPEN); Status = MRxSmbCoreCreateDirectory(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS); if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate couldn't mkdir st=%08lx\n",Status)); goto FINALLY; }
if ((mappedAttributes & (SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_ARCHIVE)) != 0) { //
//we have to set the attributes
Status = MRxSmbSetFileAttributes( SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, mappedAttributes);
if (!NT_SUCCESS(Status)) { RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate couldn't sfa st=%08lx\n",Status)); } }
if (Status == STATUS_SUCCESS) { Status = MRxSmbPseudoOpenTailFromCoreCreateDirectory( OrdinaryExchange, mappedAttributes ); }
goto FINALLY; }
//if ( (mappedOpenMode != -1) && !MustBeADirectory) {
//no pseudoOpens yet
if ( TRUE ) {
ULONG workingDisposition = Disposition; ULONG iterationcount; BOOLEAN MayNeedATruncate = FALSE;
//
// we use the disposition as a state and case out.....some are hard and some are easy
// for example, if it's CREATE then we use the CREATE_NEW to create the file but
// the resulting open is no good so we close it and open it again using the
// open. for OPEN_IF we assume that the file will be there
// and drop into create if it's not.
for (iterationcount=0;;iterationcount++) { switch (workingDisposition) { case FILE_OVERWRITE: case FILE_OVERWRITE_IF: MayNeedATruncate = TRUE; //lack of break intentional
case FILE_OPEN_IF: case FILE_OPEN: Status = MRxSmbCoreOpen(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, mappedOpenMode|mappedSharingMode, mappedAttributes); //if (Status==RxStatus(NO_SUCH_FILE)) {
// DbgPrint("%08lx %08lx %08lx\n",Status,workingDisposition,iterationcount);
// DbgBreakPoint();
//}
if (!((workingDisposition == FILE_OPEN_IF) || (workingDisposition == FILE_OVERWRITE_IF)) || (Status!=RX_MAP_STATUS(NO_SUCH_FILE)) || (iterationcount>6) )break; SmbCeResetExchange(&OrdinaryExchange->Exchange); //must reset!
case FILE_SUPERSEDE: case FILE_CREATE: Status = MRxSmbCoreCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, mappedAttributes,TRUE); //(workingDisposition==FILE_CREATE));
if (!NT_SUCCESS(Status)) { RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......createnew failed st=%08lx\n",Status)); break; }
//now, we have a network handle. BUT, it's a compatibility-mode open. since we don't want that we
// need to close and reopen with the parameters specified. there is a window here! what can i do??
Status = MRxSmbCloseAfterCoreCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS); if (!NT_SUCCESS(Status)) { RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......closeaftercreatenew failed st=%08lx\n",Status)); break; }
workingDisposition = FILE_OPEN_IF; continue; // this wraps back to the switch with a new disposition
//break;
//case FILE_SUPERSEDE:
// Status = RxStatus(NOT_SUPPORTED);
// break;
default : ASSERT(!"Bad Disposition"); Status = RX_MAP_STATUS(INVALID_PARAMETER); } break; //exit the loop
} if (!NT_SUCCESS(Status))goto FINALLY; //we may need a truncate....this is different from rdr1.
if (MayNeedATruncate && !OrdinaryExchange->Create.FileWasCreated && (OrdinaryExchange->Create.FileSizeReturnedFromOpen!=0) ) { Status = MRxSmbCoreTruncate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS, OrdinaryExchange->Create.FidReturnedFromOpen, 0 ); } goto FINALLY; }
FINALLY: RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status)); return(Status); }
NTSTATUS MRxSmbFinishGFA ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, PBYTE Response ) /*++
Routine Description:
This routine copies the response to the GetFileAttributes SMB. But, it must be called synchronously.
Arguments:
OrdinaryExchange - the exchange instance Response - the response
Return Value:
RXSTATUS - The return status for the operation
Notes:
what we do here is to put the data into the ordinary exchange...it's locked down do we could do this at DPC level
--*/ { NTSTATUS Status = RX_MAP_STATUS(SUCCESS); PFILE_BASIC_INFORMATION BasicInformation = &OrdinaryExchange->Create.FileInfo.Basic; PFILE_STANDARD_INFORMATION StandardInformation = &OrdinaryExchange->Create.FileInfo.Standard;
PSMB_PARAMS pSmbParams = (PSMB_PARAMS)Response;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishGFA\n", 0 )); SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishGFA:");
if (pSmbParams->WordCount == 10) { PRESP_QUERY_INFORMATION pQueryInformationResponse;
if (OrdinaryExchange->BytesAvailableCopy < sizeof(SMB_HEADER)+FIELD_OFFSET(RESP_QUERY_INFORMATION, Buffer)) { return STATUS_INVALID_NETWORK_RESPONSE; }
pQueryInformationResponse = (PRESP_QUERY_INFORMATION)Response;
//what we do here is to put the data into the ordinary exchange...it's locked down do
//we wcould do this at DPC level
MRxSmbPopulateFileInfoInOE( OrdinaryExchange, SmbGetUshort(&pQueryInformationResponse->FileAttributes), SmbGetUlong(&pQueryInformationResponse->LastWriteTimeInSeconds), SmbGetUlong(&pQueryInformationResponse->FileSize) );
} else if (pSmbParams->WordCount == 11) { PRESP_QUERY_INFORMATION2 pQueryInformation2Response; SMB_TIME LastWriteSmbTime; SMB_DATE LastWriteSmbDate; LARGE_INTEGER LastWriteTime; ULONG LastWriteTimeInSeconds;
if (OrdinaryExchange->BytesAvailableCopy < sizeof(SMB_HEADER)+FIELD_OFFSET(RESP_QUERY_INFORMATION2, Buffer)) { return STATUS_INVALID_NETWORK_RESPONSE; } pQueryInformation2Response = (PRESP_QUERY_INFORMATION2)Response;
RtlCopyMemory( &LastWriteSmbTime, &pQueryInformation2Response->LastWriteTime, sizeof(SMB_TIME));
RtlCopyMemory( &LastWriteSmbDate, &pQueryInformation2Response->LastWriteDate, sizeof(SMB_DATE));
LastWriteTime = MRxSmbConvertSmbTimeToTime(NULL,LastWriteSmbTime,LastWriteSmbDate);
MRxSmbTimeToSecondsSince1970( &LastWriteTime, NULL, &LastWriteTimeInSeconds);
MRxSmbPopulateFileInfoInOE( OrdinaryExchange, SmbGetUshort(&pQueryInformation2Response->FileAttributes), LastWriteTimeInSeconds, SmbGetUlong(&pQueryInformation2Response->FileDataSize) ); }
RxDbgTrace(-1, Dbg, ("MRxSmbFinishGFA returning %08lx\n", Status )); return Status; }
//CODE.IMPROVEMENT shouldn't this be in a .h file.....
NTSTATUS MRxSmbCreateFileSuccessTail ( PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, SMBFCB_HOLDING_STATE *SmbFcbHoldingState, RX_FILE_TYPE StorageType, SMB_FILE_ID Fid, ULONG ServerVersion, UCHAR OplockLevel, ULONG CreateAction, PSMBPSE_FILEINFO_BUNDLE FileInfo );
NTSTATUS MRxSmbFinishCoreCreate ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, PRESP_CREATE Response ) /*++
Routine Description:
This routine copies the fid from a core create response. it does not finish the fcb......if a compatibility mode open is acceptable then it could.
Arguments:
OrdinaryExchange - the exchange instance Response - the response
Return Value:
RXSTATUS - The return status for the operation
--*/ { NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreCreate\n", 0 )); SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreCreate:");
if (Response->WordCount != 1 || SmbGetUshort(&Response->ByteCount) != 0) { Status = STATUS_INVALID_NETWORK_RESPONSE; OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE; } else { OrdinaryExchange->Create.FidReturnedFromCreate = SmbGetUshort(&Response->Fid); OrdinaryExchange->Create.FileWasCreated = TRUE; //notice that we didn't finish here! we should IFF a compatibilty-mode open is okay
}
RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreCreate returning %08lx\n", Status )); return Status; }
#define JUST_USE_THE_STUFF_IN_THE_OE (0xfbad)
VOID MRxSmbPopulateFileInfoInOE( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, USHORT FileAttributes, ULONG LastWriteTimeInSeconds, ULONG FileSize ) { PFILE_BASIC_INFORMATION BasicInformation = &OrdinaryExchange->Create.FileInfo.Basic; PFILE_STANDARD_INFORMATION StandardInformation = &OrdinaryExchange->Create.FileInfo.Standard;
BasicInformation->FileAttributes = MRxSmbMapSmbAttributes(FileAttributes); StandardInformation->NumberOfLinks = 1; BasicInformation->CreationTime.QuadPart = 0; BasicInformation->LastAccessTime.QuadPart = 0; MRxSmbSecondsSince1970ToTime(LastWriteTimeInSeconds, SmbCeGetExchangeServer(OrdinaryExchange), &BasicInformation->LastWriteTime); BasicInformation->ChangeTime.QuadPart = 0; StandardInformation->AllocationSize.QuadPart = FileSize; //rdr1 actually rounds up based of svr disk attribs
StandardInformation->EndOfFile.QuadPart = FileSize; StandardInformation->Directory = BooleanFlagOn(BasicInformation->FileAttributes,FILE_ATTRIBUTE_DIRECTORY); }
NTSTATUS MRxSmbFinishCoreOpen ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, PRESP_OPEN Response ) /*++
Routine Description:
This routine finishes a core open.
Arguments:
OrdinaryExchange - the exchange instance Response - the response
Return Value:
RXSTATUS - The return status for the operation
--*/ {
NTSTATUS Status = RX_MAP_STATUS(SUCCESS); PRX_CONTEXT RxContext = OrdinaryExchange->RxContext; PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
RX_FILE_TYPE StorageType; SMB_FILE_ID Fid; ULONG CreateAction;
ULONG FileSize;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreOpen\n", 0 )); SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreOpen:");
if (Response->WordCount != 7 || SmbGetUshort(&Response->ByteCount) != 0) { Status = STATUS_INVALID_NETWORK_RESPONSE; OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE; goto FINALLY; }
if (OrdinaryExchange->BytesAvailableCopy < sizeof(SMB_HEADER)+FIELD_OFFSET(RESP_OPEN, Buffer)) { Status = STATUS_INVALID_NETWORK_RESPONSE; OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE; goto FINALLY; }
StorageType = FileTypeFile; Fid = SmbGetUshort(&Response->Fid); OrdinaryExchange->Create.FidReturnedFromOpen = Fid; FileSize = OrdinaryExchange->Create.FileSizeReturnedFromOpen = SmbGetUlong(&Response->DataSize);
CreateAction = (OrdinaryExchange->Create.FileWasCreated)?FILE_CREATED : (OrdinaryExchange->Create.FileWasTruncated)?FILE_OVERWRITTEN :FILE_OPENED;
MRxSmbPopulateFileInfoInOE( OrdinaryExchange, SmbGetUshort(&Response->FileAttributes), SmbGetUlong(&Response->LastWriteTimeInSeconds), FileSize );
pFileInfo->Basic.FileAttributes = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes; pFileInfo->Basic.CreationTime = OrdinaryExchange->Create.FileInfo.Basic.CreationTime; pFileInfo->Basic.LastAccessTime = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime; pFileInfo->Basic.LastWriteTime = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime; pFileInfo->Basic.ChangeTime = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime; pFileInfo->Standard.NumberOfLinks = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks; pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize; pFileInfo->Standard.EndOfFile = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile; pFileInfo->Standard.Directory = FALSE;
//CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
Status = MRxSmbCreateFileSuccessTail ( RxContext, &OrdinaryExchange->Create.MustRegainExclusiveResource, &OrdinaryExchange->SmbFcbHoldingState, StorageType, Fid, OrdinaryExchange->ServerVersion, SMB_OPLOCK_LEVEL_NONE, CreateAction, pFileInfo);
FINALLY: IF_DEBUG{ RxCaptureFcb; RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreOpen returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState )); } return Status; }
NTSTATUS MRxSmbPseudoOpenTailFromCoreCreateDirectory ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, USHORT Attributes ) /*++
Routine Description:
This routine finishes a core create directory. but, it is not called from the receive routine......
Arguments:
OrdinaryExchange - the exchange instance
Return Value:
RXSTATUS - The return status for the operation
--*/ {
NTSTATUS Status = RX_MAP_STATUS(SUCCESS); PRX_CONTEXT RxContext = OrdinaryExchange->RxContext; RxCaptureFobx; PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
RX_FILE_TYPE StorageType; SMB_FILE_ID Fid; ULONG CreateAction;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreCreateDirectory\n", 0 )); SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreCreateDirectory:");
StorageType = FileTypeDirectory; Fid = 0xbadd;
CreateAction = FILE_CREATED; MRxSmbPopulateFileInfoInOE( OrdinaryExchange, Attributes, 0, 0 );
pFileInfo->Basic.FileAttributes = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes; pFileInfo->Basic.CreationTime = OrdinaryExchange->Create.FileInfo.Basic.CreationTime; pFileInfo->Basic.LastAccessTime = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime; pFileInfo->Basic.LastWriteTime = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime; pFileInfo->Basic.ChangeTime = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime; pFileInfo->Standard.NumberOfLinks = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks; pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize; pFileInfo->Standard.EndOfFile = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile; pFileInfo->Standard.Directory = TRUE;
//CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
smbSrvOpen->Flags |= SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN; //this indicates a pseudoopen to success tail
Status = MRxSmbCreateFileSuccessTail ( RxContext, &OrdinaryExchange->Create.MustRegainExclusiveResource, &OrdinaryExchange->SmbFcbHoldingState, StorageType, Fid, OrdinaryExchange->ServerVersion, SMB_OPLOCK_LEVEL_NONE, CreateAction, pFileInfo);
IF_DEBUG{ RxCaptureFcb; RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreCreateDirectory returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState )); } return Status; }
NTSTATUS MRxSmbPseudoOpenTailFromFakeGFAResponse ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, RX_FILE_TYPE StorageType ) /*++
Routine Description:
This routine finishes a pseudoopen from faked up information. Basically, we fill in the information that would have been obtained on a GET_FILE_ATTRIBUTES smb and then call the PseudoOpenFromGFA routine
Arguments:
OrdinaryExchange - the exchange instance StorageType - the type of thing that this is supposed to be. If it's supposed to be a directory then we set the attributes bit in the GFA info.
Return Value:
RXSTATUS - The return status for the operation
--*/ { NTSTATUS Status = RX_MAP_STATUS(SUCCESS); USHORT Attributes = 0;
PAGED_CODE();
RtlZeroMemory( &OrdinaryExchange->Create.FileInfo, sizeof(OrdinaryExchange->Create.FileInfo));
if (StorageType == FileTypeDirectory) { Attributes = SMB_FILE_ATTRIBUTE_DIRECTORY; }
MRxSmbPopulateFileInfoInOE(OrdinaryExchange,Attributes,0,0); OrdinaryExchange->Create.StorageTypeFromGFA = StorageType;
return( MRxSmbPseudoOpenTailFromGFAResponse (OrdinaryExchange) ); }
NTSTATUS MRxSmbPseudoOpenTailFromGFAResponse ( PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange ) /*++
Routine Description:
This routine finishes a pseudoopen from the information obtained on a GET_FILE_ATTRIBUTES smb.
Arguments:
OrdinaryExchange - the exchange instance
Return Value:
RXSTATUS - The return status for the operation
--*/ {
NTSTATUS Status = RX_MAP_STATUS(SUCCESS); PRX_CONTEXT RxContext = OrdinaryExchange->RxContext; PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen); PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
SMB_FILE_ID Fid; ULONG CreateAction;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse\n")); SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishPseudoOpenFromGFAResponse:");
Fid = 0xbadd;
CreateAction = FILE_OPENED;
pFileInfo->Basic.FileAttributes = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes; pFileInfo->Basic.CreationTime = OrdinaryExchange->Create.FileInfo.Basic.CreationTime; pFileInfo->Basic.LastAccessTime = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime; pFileInfo->Basic.LastWriteTime = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime; pFileInfo->Basic.ChangeTime = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime; pFileInfo->Standard.NumberOfLinks = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks; pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize; pFileInfo->Standard.EndOfFile = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile; pFileInfo->Standard.Directory = (OrdinaryExchange->Create.StorageTypeFromGFA == FileTypeDirectory);
//CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
// it seems to me that everything but the fid coudl be done that way and the success tail routine
// moved to the wrapper
smbSrvOpen->Flags |= SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN; //this indicates a pseudoopen to success tail
Status = MRxSmbCreateFileSuccessTail ( RxContext, &OrdinaryExchange->Create.MustRegainExclusiveResource, &OrdinaryExchange->SmbFcbHoldingState, OrdinaryExchange->Create.StorageTypeFromGFA, Fid, OrdinaryExchange->ServerVersion, SMB_OPLOCK_LEVEL_NONE, CreateAction, pFileInfo);
if (Status == STATUS_SUCCESS) { if (smbSrvOpen->DeferredOpenContext == NULL) { // if it is a remote boot server file, it already has a deferred open context created
// on MRxSmbCreateFileSuccessTail
Status = MRxSmbConstructDeferredOpenContext(RxContext); } else { // The flag has been cleared when a deferred open context was created for a remote boot server file.
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN); } }
if (Status!=STATUS_SUCCESS) { RxDbgTrace(-1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse construct dfo failed %08lx \n",Status)); }
IF_DEBUG{ RxCaptureFcb; RxDbgTrace(-1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState )); } return Status; }
LARGE_INTEGER MRxSmbConvertSmbTimeToTime ( //IN PSMB_EXCHANGE Exchange OPTIONAL,
IN PSMBCE_SERVER Server OPTIONAL, IN SMB_TIME Time, IN SMB_DATE Date )
/*++
Routine Description:
This routine converts an SMB time to an NT time structure.
Arguments:
IN SMB_TIME Time - Supplies the time of day to convert IN SMB_DATE Date - Supplies the day of the year to convert IN supplies the server for tz bias.
Return Value:
LARGE_INTEGER - Time structure describing input time.
--*/
{ TIME_FIELDS TimeFields; LARGE_INTEGER OutputTime;
PAGED_CODE();
//
// This routine cannot be paged because it is called from both the
// MRxSmbFileDiscardableSection and the MRxSmbVCDiscardableSection.
//
if (SmbIsTimeZero(&Date) && SmbIsTimeZero(&Time)) { OutputTime.LowPart = OutputTime.HighPart = 0; } else { TimeFields.Year = Date.Struct.Year + (USHORT )1980; TimeFields.Month = Date.Struct.Month; TimeFields.Day = Date.Struct.Day;
TimeFields.Hour = Time.Struct.Hours; TimeFields.Minute = Time.Struct.Minutes; TimeFields.Second = Time.Struct.TwoSeconds*(USHORT )2; TimeFields.Milliseconds = 0;
//
// Make sure that the times specified in the SMB are reasonable
// before converting them.
//
if (TimeFields.Year < 1601) { TimeFields.Year = 1601; }
if (TimeFields.Month > 12) { TimeFields.Month = 12; }
if (TimeFields.Hour >= 24) { TimeFields.Hour = 23; } if (TimeFields.Minute >= 60) { TimeFields.Minute = 59; } if (TimeFields.Second >= 60) { TimeFields.Second = 59;
}
if (!RtlTimeFieldsToTime(&TimeFields, &OutputTime)) { OutputTime.HighPart = 0; OutputTime.LowPart = 0;
return OutputTime; }
#ifndef WIN9X
if (ARGUMENT_PRESENT(Server)) { OutputTime.QuadPart = OutputTime.QuadPart + Server->TimeZoneBias.QuadPart; }
ExLocalTimeToSystemTime(&OutputTime, &OutputTime); #else
OutputTime.HighPart = 0; OutputTime.LowPart = 0; #endif
}
return OutputTime;
}
BOOLEAN MRxSmbConvertTimeToSmbTime ( IN PLARGE_INTEGER InputTime, IN PSMB_EXCHANGE Exchange OPTIONAL, OUT PSMB_TIME Time, OUT PSMB_DATE Date )
/*++
Routine Description:
This routine converts an NT time structure to an SMB time.
Arguments:
IN LARGE_INTEGER InputTime - Supplies the time to convert. OUT PSMB_TIME Time - Returns the converted time of day. OUT PSMB_DATE Date - Returns the converted day of the year.
Return Value:
BOOLEAN - TRUE if input time could be converted.
--*/
{ TIME_FIELDS TimeFields;
PAGED_CODE();
if (InputTime->LowPart == 0 && InputTime->HighPart == 0) { Time->Ushort = Date->Ushort = 0; } else { LARGE_INTEGER LocalTime;
ExSystemTimeToLocalTime(InputTime, &LocalTime);
if (ARGUMENT_PRESENT(Exchange)) { PSMBCE_SERVER Server = SmbCeGetExchangeServer(Exchange); LocalTime.QuadPart -= Server->TimeZoneBias.QuadPart; }
RtlTimeToTimeFields(&LocalTime, &TimeFields);
if (TimeFields.Year < 1980) { return FALSE; }
Date->Struct.Year = (USHORT )(TimeFields.Year - 1980); Date->Struct.Month = TimeFields.Month; Date->Struct.Day = TimeFields.Day;
Time->Struct.Hours = TimeFields.Hour; Time->Struct.Minutes = TimeFields.Minute;
//
// When converting from a higher granularity time to a lesser
// granularity time (seconds to 2 seconds), always round up
// the time, don't round down.
//
Time->Struct.TwoSeconds = (TimeFields.Second + (USHORT)1) / (USHORT )2;
}
return TRUE; }
BOOLEAN MRxSmbTimeToSecondsSince1970 ( IN PLARGE_INTEGER CurrentTime, IN PSMBCE_SERVER Server OPTIONAL, OUT PULONG SecondsSince1970 ) /*++
Routine Description:
This routine returns the CurrentTime in UTC and returns the equivalent current time in the servers timezone.
Arguments:
IN PLARGE_INTEGER CurrentTime - Supplies the current system time in UTC.
IN PSMBCE_SERVER Server - Supplies the difference in timezones between the server and the workstation. If not supplied then the assumption is that they are in the same timezone.
OUT PULONG SecondsSince1970 - Returns the # of seconds since 1970 in the servers timezone or MAXULONG if conversion fails.
Return Value:
BOOLEAN - TRUE if the time could be converted.
--*/ { LARGE_INTEGER ServerTime; LARGE_INTEGER TempTime; BOOLEAN ReturnValue;
PAGED_CODE();
if (ARGUMENT_PRESENT(Server) && ((*CurrentTime).QuadPart != 0)) {
TempTime.QuadPart = (*CurrentTime).QuadPart - Server->TimeZoneBias.QuadPart;
ExSystemTimeToLocalTime(&TempTime, &ServerTime); } else { ExSystemTimeToLocalTime(CurrentTime, &ServerTime); }
ReturnValue = RtlTimeToSecondsSince1970(&ServerTime, SecondsSince1970);
if ( ReturnValue == FALSE ) { //
// We can't represent the time legally, peg it at
// the max legal time.
//
*SecondsSince1970 = MAXULONG; }
return ReturnValue; }
VOID MRxSmbSecondsSince1970ToTime ( IN ULONG SecondsSince1970, //IN PSMB_EXCHANGE Exchange OPTIONAL,
IN PSMBCE_SERVER Server, OUT PLARGE_INTEGER CurrentTime ) /*++
Routine Description:
This routine returns the Local system time derived from a time in seconds in the servers timezone.
Arguments:
IN ULONG SecondsSince1970 - Supplies the # of seconds since 1970 in servers timezone.
IN PSMB_EXCHANGE Exchange - Supplies the difference in timezones between the server and the workstation. If not supplied then the assumption is that they are in the same timezone.
OUT PLARGE_INTEGER CurrentTime - Returns the current system time in UTC.
Return Value:
None.
--*/
{ LARGE_INTEGER LocalTime;
PAGED_CODE();
RtlSecondsSince1970ToTime (SecondsSince1970, &LocalTime);
ExLocalTimeToSystemTime(&LocalTime, CurrentTime);
if (ARGUMENT_PRESENT(Server)) { (*CurrentTime).QuadPart = (*CurrentTime).QuadPart + Server->TimeZoneBias.QuadPart; }
return;
}
ULONG MRxSmbMapSmbAttributes ( IN USHORT SmbAttribs )
/*++
Routine Description:
This routine maps an SMB (DOS/OS2) file attribute into an NT file attribute.
Arguments:
IN USHORT SmbAttribs - Supplies the SMB attribute to map.
Return Value:
ULONG - NT Attribute mapping SMB attribute
--*/
{ ULONG Attributes = 0;
PAGED_CODE();
if (SmbAttribs==0) { Attributes = FILE_ATTRIBUTE_NORMAL; } else {
ASSERT (SMB_FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY); ASSERT (SMB_FILE_ATTRIBUTE_HIDDEN == FILE_ATTRIBUTE_HIDDEN); ASSERT (SMB_FILE_ATTRIBUTE_SYSTEM == FILE_ATTRIBUTE_SYSTEM); ASSERT (SMB_FILE_ATTRIBUTE_ARCHIVE == FILE_ATTRIBUTE_ARCHIVE); ASSERT (SMB_FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY);
Attributes = SmbAttribs & FILE_ATTRIBUTE_VALID_FLAGS; } return Attributes; }
USHORT MRxSmbMapDisposition ( IN ULONG Disposition )
/*++
Routine Description:
This routine takes an NT disposition, and maps it into an OS/2 CreateAction to be put into an SMB.
Arguments:
IN ULONG Disposition - Supplies the NT disposition to map.
Return Value:
USHORT - OS/2 Access mapping that maps NT access
--*/
{ PAGED_CODE();
switch (Disposition) { case FILE_OVERWRITE_IF: case FILE_SUPERSEDE: return SMB_OFUN_OPEN_TRUNCATE | SMB_OFUN_CREATE_CREATE; break;
case FILE_CREATE: return SMB_OFUN_OPEN_FAIL | SMB_OFUN_CREATE_CREATE; break;
case FILE_OVERWRITE: return SMB_OFUN_OPEN_TRUNCATE | SMB_OFUN_CREATE_FAIL; break;
case FILE_OPEN: return SMB_OFUN_OPEN_OPEN | SMB_OFUN_CREATE_FAIL; break;
case FILE_OPEN_IF: return SMB_OFUN_OPEN_OPEN | SMB_OFUN_CREATE_CREATE; break;
default: //InternalError(("Unknown disposition passed to MRxSmbMapDisposition"));
//MRxSmbInternalError(EVENT_RDR_DISPOSITION);
return 0; break; } }
ULONG MRxSmbUnmapDisposition ( IN USHORT SmbDisposition, ULONG Disposition )
/*++
Routine Description:
This routine takes an OS/2 disposition and maps it into an NT disposition.
Arguments:
IN USHORT SmbDisposition - Supplies the OS/2 disposition to map.
Return Value:
ULONG - NT disposition mapping OS/2 disposition
--*/
{ ULONG MapDisposition;
PAGED_CODE();
//
// Mask off oplocked bit.
//
switch (SmbDisposition & 0x7fff) {
case SMB_OACT_OPENED: MapDisposition = FILE_OPENED; break;
case SMB_OACT_CREATED: MapDisposition = FILE_CREATED; break;
case SMB_OACT_TRUNCATED: MapDisposition = FILE_OVERWRITTEN; break;
default: MapDisposition = Disposition; }
return MapDisposition; }
USHORT MRxSmbMapDesiredAccess ( IN ULONG DesiredAccess )
/*++
Routine Description:
This routine takes an NT DesiredAccess value and converts it to an OS/2 access mode.
Arguments:
IN ULONG DesiredAccess - Supplies the NT desired access to map.
Return Value:
USHORT - The mapped OS/2 access mode that compares to the NT code specified. If there is no mapping for the NT code, we return -1 as the access mode.
--*/
{ PAGED_CODE();
//
// If the user asked for both read and write access, return read/write.
//
if ((DesiredAccess & FILE_READ_DATA)&&(DesiredAccess & FILE_WRITE_DATA)) { return SMB_DA_ACCESS_READ_WRITE; }
//
// If the user requested WRITE_DATA, return write.
//
if (DesiredAccess & FILE_WRITE_DATA) { return SMB_DA_ACCESS_WRITE; }
//
// If the user requested READ_DATA, return read.
//
if (DesiredAccess & FILE_READ_DATA) { return SMB_DA_ACCESS_READ; }
//
// If the user requested ONLY execute access, then request execute
// access. Execute access is the "weakest" of the possible desired
// accesses, so it takes least precedence.
//
if (DesiredAccess & FILE_EXECUTE) { return SMB_DA_ACCESS_EXECUTE; }
//
// If we couldn't figure out what we were doing, return -1
//
// Among the attributes that we do not map are:
//
// FILE_READ_ATTRIBUTES
// FILE_WRITE_ATTRIBUTES
// FILE_READ_EAS
// FILE_WRITE_EAS
//
// dprintf(DPRT_ERROR, ("Could not map DesiredAccess of %08lx\n", DesiredAccess));
return (USHORT)0; }
USHORT MRxSmbMapShareAccess ( IN USHORT ShareAccess )
/*++
Routine Description:
This routine takes an NT ShareAccess value and converts it to an OS/2 sharing mode.
Arguments:
IN USHORT ShareAccess - Supplies the OS/2 share access to map.
Return Value:
USHORT - The mapped OS/2 sharing mode that compares to the NT code specified
--*/
{ USHORT ShareMode = SMB_DA_SHARE_EXCLUSIVE;
PAGED_CODE();
if ((ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE)) == (FILE_SHARE_READ | FILE_SHARE_WRITE)) { ShareMode = SMB_DA_SHARE_DENY_NONE; } else if (ShareAccess & FILE_SHARE_READ) { ShareMode = SMB_DA_SHARE_DENY_WRITE; } else if (ShareAccess & FILE_SHARE_WRITE) { ShareMode = SMB_DA_SHARE_DENY_READ; }
// else if (ShareAccess & FILE_SHARE_DELETE) {
// InternalError(("Support for FILE_SHARE_DELETE NYI\n"));
// }
return ShareMode;
}
USHORT MRxSmbMapFileAttributes ( IN ULONG FileAttributes )
/*++
Routine Description:
This routine takes an NT file attribute mapping and converts it into an OS/2 file attribute definition.
Arguments:
IN ULONG FileAttributes - Supplies the file attributes to map.
Return Value:
USHORT
--*/
{ USHORT ResultingAttributes = 0;
PAGED_CODE();
if (FileAttributes==FILE_ATTRIBUTE_NORMAL) { return ResultingAttributes; }
if (FileAttributes & FILE_ATTRIBUTE_READONLY) { ResultingAttributes |= SMB_FILE_ATTRIBUTE_READONLY; }
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN) { ResultingAttributes |= SMB_FILE_ATTRIBUTE_HIDDEN; }
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM) { ResultingAttributes |= SMB_FILE_ATTRIBUTE_SYSTEM; } if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE) { ResultingAttributes |= SMB_FILE_ATTRIBUTE_ARCHIVE; } return ResultingAttributes; }
|