/*++ 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; }