You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2600 lines
87 KiB
2600 lines
87 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|