806 lines
28 KiB
C
806 lines
28 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
rename.c
|
||
|
||
Abstract:
|
||
|
||
This module implements rename in the smb minirdr.
|
||
|
||
Author:
|
||
|
||
Balan Sethu Raman [SethuR] 7-March-1995
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, MRxSmbRename)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildRename)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildDeleteForRename)
|
||
#pragma alloc_text(PAGE, SmbPseExchangeStart_Rename)
|
||
#pragma alloc_text(PAGE, MRxSmbFinishRename)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildCheckEmptyDirectory)
|
||
#pragma alloc_text(PAGE, SmbPseExchangeStart_SetDeleteDisposition)
|
||
#pragma alloc_text(PAGE, MRxSmbSetDeleteDisposition)
|
||
#endif
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_FILEINFO)
|
||
|
||
NTSTATUS
|
||
SmbPseExchangeStart_Rename(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
);
|
||
NTSTATUS
|
||
SmbPseExchangeStart_SetDeleteDisposition(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
);
|
||
|
||
|
||
|
||
MRxSmbRename(
|
||
IN PRX_CONTEXT RxContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine does a rename by
|
||
1) purge and remove buffering rights....setup the FCB so that no more stuff can get thru.
|
||
2) closing its fid along with any deferred fids.
|
||
3) if replace...do a delete
|
||
4) do a downlevel smb_com_rename.
|
||
|
||
there are many provisos but i think that this is the best balance. it is a real shame that the
|
||
NT-->NT path was never implemented in nt4.0 or before.
|
||
|
||
Arguments:
|
||
|
||
RxContext - the RDBSS context
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
|
||
RxCaptureFcb; RxCaptureFobx;
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
|
||
|
||
PAGED_CODE();
|
||
|
||
RETRY:
|
||
RxDbgTrace(0, Dbg, ("MRxSmbRename\n", 0 ));
|
||
|
||
ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
//ASSERT( RxContext->Info.FileInformationClass == FileRenameInformation); //later we'll do downlevel delete here as well
|
||
|
||
Status = SmbPseCreateOrdinaryExchange(RxContext,
|
||
capFobx->pSrvOpen->pVNetRoot,
|
||
SMBPSE_OE_FROM_RENAME,
|
||
SmbPseExchangeStart_Rename,
|
||
&OrdinaryExchange);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
RxDbgTrace(0, Dbg, ("Couldn't get the smb buf!\n"));
|
||
return(Status);
|
||
}
|
||
|
||
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
|
||
|
||
ASSERT (Status != RX_MAP_STATUS(PENDING));
|
||
|
||
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
||
|
||
if (Status == STATUS_RETRY) {
|
||
goto RETRY;
|
||
}
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
// create the name based file not found cache
|
||
MRxSmbCacheFileNotFound(RxContext);
|
||
// invalide the file not found cache for the new name if exists
|
||
MRxSmbInvalidateFileNotFoundCacheForRename(RxContext);
|
||
}
|
||
|
||
// invalidate the name based file info cache
|
||
MRxSmbInvalidateFileInfoCache(RxContext);
|
||
MRxSmbInvalidateInternalFileInfoCache(RxContext);
|
||
|
||
RxDbgTrace(0, Dbg, ("MRxSmbRename exit with status=%08lx\n", Status ));
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildRename (
|
||
PSMBSTUFFER_BUFFER_STATE StufferState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This builds a Rename SMB. we don't have to worry about login id and such
|
||
since that is done by the connection engine....pretty neat huh? all we have to do
|
||
is to format up the bits.
|
||
|
||
Arguments:
|
||
|
||
StufferState - the state of the smbbuffer from the stuffer's point of view
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS
|
||
SUCCESS
|
||
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
|
||
|
||
Notes:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS StufferStatus;
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
RxCaptureFcb;RxCaptureFobx;
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
|
||
|
||
PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
|
||
UNICODE_STRING RenameName;
|
||
USHORT SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_DIRECTORY;
|
||
|
||
PAGED_CODE();
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbBuildRename\n", 0 ));
|
||
|
||
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
RenameName.Buffer = &RenameInformation->FileName[0];
|
||
RenameName.Length = (USHORT)RenameInformation->FileNameLength;
|
||
|
||
if (RxContext->Info.FileInformationClass == FileRenameInformation) {
|
||
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_RENAME,
|
||
SMB_REQUEST_SIZE(RENAME),
|
||
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
|
||
);
|
||
|
||
MRxSmbDumpStufferState (1100,"SMB w/ RENAME before stuffing",StufferState);
|
||
|
||
MRxSmbStuffSMB (StufferState,
|
||
"0wB",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 1
|
||
SearchAttributes, // w _USHORT( SearchAttributes );
|
||
SMB_WCT_CHECK(1) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
|
||
// UCHAR Buffer[1]; // Buffer containing:
|
||
// //UCHAR BufferFormat1; // 0x04 -- ASCII
|
||
// //UCHAR OldFileName[]; // Old file name
|
||
// //UCHAR BufferFormat2; // 0x04 -- ASCII
|
||
// //UCHAR NewFileName[]; // New file name
|
||
);
|
||
} else {
|
||
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_NT_RENAME,
|
||
SMB_REQUEST_SIZE(NTRENAME),
|
||
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
|
||
);
|
||
|
||
MRxSmbDumpStufferState (1100,"SMB w/ NTRENAME before stuffing",StufferState);
|
||
|
||
MRxSmbStuffSMB (StufferState,
|
||
"0wwdB",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 1
|
||
SearchAttributes, // w _USHORT( SearchAttributes );
|
||
SMB_NT_RENAME_SET_LINK_INFO, // w _USHORT( InformationLevel );
|
||
0, // d _ULONG( ClusterCount );
|
||
SMB_WCT_CHECK(4) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
|
||
// UCHAR Buffer[1]; // Buffer containing:
|
||
// //UCHAR BufferFormat1; // 0x04 -- ASCII
|
||
// //UCHAR OldFileName[]; // Old file name
|
||
// //UCHAR BufferFormat2; // 0x04 -- ASCII
|
||
// //UCHAR NewFileName[]; // New file name
|
||
);
|
||
}
|
||
|
||
//CODE.IMPROVEMENT we don't need to copy here, we can just Mdl like in writes
|
||
// of course, this causes a problem later for an NCB rdr in that
|
||
// you can't andX without copying....also, the stuffer would probably
|
||
// get confused
|
||
//Code.IMPROVEMENT since you know that you're gonna copy, we might as well
|
||
// include this earlier unless we want to MDL it in
|
||
Status = MRxSmbStuffSMB (StufferState,
|
||
"44!", RemainingName, &RenameName );
|
||
|
||
MRxSmbDumpStufferState (700,"SMB w/ RENAME after stuffing",StufferState);
|
||
//ASSERT(!"Now it's stuffed");
|
||
|
||
FINALLY:
|
||
RxDbgTraceUnIndent(-1,Dbg);
|
||
return(Status);
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildDeleteForRename (
|
||
PSMBSTUFFER_BUFFER_STATE StufferState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This builds a Delete SMB. we don't have to worry about login id and such
|
||
since that is done by the connection engine....pretty neat huh? all we have to do
|
||
is to format up the bits.
|
||
|
||
Arguments:
|
||
|
||
StufferState - the state of the smbbuffer from the stuffer's point of view
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS
|
||
SUCCESS
|
||
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
|
||
|
||
Notes:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS StufferStatus;
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
RxCaptureFcb;RxCaptureFobx;
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
|
||
|
||
PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
|
||
UNICODE_STRING RenameName;
|
||
ULONG SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN; // a la rdr1
|
||
|
||
PAGED_CODE();
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbBuild Delete 4RENAME\n", 0 ));
|
||
|
||
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
RenameName.Buffer = &RenameInformation->FileName[0];
|
||
RenameName.Length = (USHORT)RenameInformation->FileNameLength;
|
||
|
||
|
||
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 Delete 4RENAME 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:
|
||
&RenameName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
|
||
// //UCHAR FileName[]; // File name
|
||
);
|
||
|
||
MRxSmbDumpStufferState (700,"SMB w/ Delete 4RENAME after stuffing",StufferState);
|
||
//ASSERT(!"Now it's stuffed");
|
||
|
||
FINALLY:
|
||
RxDbgTraceUnIndent(-1,Dbg);
|
||
return(Status);
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
SmbPseExchangeStart_Rename(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the start routine for rename and downlevel delete.
|
||
|
||
Arguments:
|
||
|
||
pExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
|
||
RxCaptureFcb; RxCaptureFobx;
|
||
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
||
|
||
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
||
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
||
|
||
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
|
||
ULONG SmbLength;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Rename\n", 0 ));
|
||
|
||
ASSERT(OrdinaryExchange->Type == ORDINARY_EXCHANGE);
|
||
ASSERT(!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
|
||
|
||
//first we have to close the fid....if it's a directory, we close the search handle as well
|
||
//CODE.IMPROVEMENT do we have to do that for NT servers.....or will the server close them auto.
|
||
|
||
MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
|
||
ASSERT (StufferState->CurrentCommand == SMB_COM_NO_ANDX_COMMAND);
|
||
|
||
if( (TypeOfOpen==RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
|
||
&& FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN) ){
|
||
// we have a search handle open.....close it
|
||
NTSTATUS Status2 = MRxSmbBuildFindClose(StufferState);
|
||
|
||
if (Status2 == RX_MAP_STATUS(SUCCESS)) {
|
||
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_FINDCLOSE
|
||
);
|
||
}
|
||
|
||
ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
|
||
ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST);
|
||
|
||
if (smbFobx->Enumeration.ResumeInfo!=NULL) {
|
||
RxFreePool(smbFobx->Enumeration.ResumeInfo);
|
||
smbFobx->Enumeration.ResumeInfo = NULL;
|
||
}
|
||
}
|
||
|
||
if (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
|
||
COVERED_CALL(MRxSmbBuildClose(StufferState));
|
||
|
||
// we also get here when hardlink is being created. We want to
|
||
// set the rename flag only when the file is really renamed
|
||
// otherwise other operations such as flush etc. start to fail because
|
||
// the flag indicates that the file has been renamed when it isn't.
|
||
if(RxContext->Info.FileInformationClass == FileRenameInformation)
|
||
{
|
||
SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_FILE_RENAMED);
|
||
}
|
||
|
||
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_CLOSE
|
||
);
|
||
|
||
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
|
||
}
|
||
|
||
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
|
||
|
||
//
|
||
// the fid is now closed and we are almost ready to do the rename. first, tho, we have
|
||
// to check for ReplaceIfExists. our implementation here is the same as rdr1....we pop out
|
||
// a smb_com_delete, which only works for a file. be like mike!! remember to ignore any errors....
|
||
|
||
if (0) {
|
||
DbgPrint("RxContext->Info.ReplaceIfExists %08lx %02lx\n",
|
||
&RxContext->Info.ReplaceIfExists,
|
||
RxContext->Info.ReplaceIfExists);
|
||
if (0) {
|
||
//DbgBreakPoint();
|
||
}
|
||
}
|
||
|
||
if (RxContext->Info.ReplaceIfExists) {
|
||
NTSTATUS DeleteStatus;
|
||
PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
|
||
UNICODE_STRING RenameName;
|
||
BOOLEAN CaseInsensitive;
|
||
|
||
CaseInsensitive= BooleanFlagOn(capFcb->pNetRoot->pSrvCall->Flags,SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES);
|
||
RenameName.Buffer = &RenameInformation->FileName[0];
|
||
RenameName.Length = (USHORT)RenameInformation->FileNameLength;
|
||
|
||
// We cannot delete the file that is renamed as its own.
|
||
if (RtlCompareUnicodeString(RemainingName,
|
||
&RenameName,
|
||
CaseInsensitive)) {
|
||
DeleteStatus = MRxSmbBuildDeleteForRename(StufferState);
|
||
if (DeleteStatus==STATUS_SUCCESS) {
|
||
|
||
DeleteStatus = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_DELETE_FOR_RENAME);
|
||
}
|
||
} else {
|
||
if ( !CaseInsensitive || (CaseInsensitive &&
|
||
!RtlCompareUnicodeString(RemainingName,&RenameName,FALSE)) ) {
|
||
Status = STATUS_SUCCESS;
|
||
goto FINALLY;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// now do the rename..........
|
||
|
||
Status = MRxSmbBuildRename(StufferState);
|
||
SmbLength = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
|
||
if ( (Status == STATUS_BUFFER_OVERFLOW)
|
||
|| (SmbLength>pServer->MaximumBufferSize) ){
|
||
RxDbgTrace(0, Dbg, ("MRxSmbRename - name too long\n", 0 ));
|
||
Status = STATUS_OBJECT_NAME_INVALID;
|
||
}
|
||
|
||
if (Status!=STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_RENAME
|
||
);
|
||
|
||
FINALLY:
|
||
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Rename exit w %08lx\n", Status ));
|
||
return Status;
|
||
}
|
||
|
||
#if 0
|
||
NTSTATUS
|
||
MRxSmbFinishRename (
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
||
PRESP_RENAME Response
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine actually gets the stuff out of the Rename response and finishes the close.
|
||
|
||
Arguments:
|
||
|
||
OrdinaryExchange - the exchange instance
|
||
Response - the response
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbFinishRename\n", 0 ));
|
||
SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishRename:");
|
||
|
||
if (Response->WordCount != 0 ||
|
||
SmbGetUshort(&Response->ByteCount) != 0) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
} else {
|
||
smbSrvOpen->Fid = 0xffff;
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbFinishRename returning %08lx\n", Status ));
|
||
return Status;
|
||
}
|
||
#endif
|
||
|
||
extern UNICODE_STRING MRxSmbAll8dot3Files;
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildCheckEmptyDirectory (
|
||
PSMBSTUFFER_BUFFER_STATE StufferState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This builds a FindFirst SMB.
|
||
|
||
Arguments:
|
||
|
||
StufferState - the state of the smbbuffer from the stuffer's point of view
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS
|
||
SUCCESS
|
||
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
|
||
|
||
Notes:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
RxCaptureFcb;
|
||
|
||
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
|
||
ULONG ResumeKeyLength = 0;
|
||
|
||
UNICODE_STRING FindFirstPattern;
|
||
|
||
// SearchAttributes is hardcoded to the magic number 0x16 CODE.IMPROVEMENT.ASHAMED use a macro!!!
|
||
ULONG SearchAttributes =
|
||
(SMB_FILE_ATTRIBUTE_DIRECTORY
|
||
| SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN);
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbBuildCheckEmptyDirectory \n"));
|
||
|
||
if (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey == NULL) {
|
||
PUNICODE_STRING DirectoryName = RemainingName;
|
||
PUNICODE_STRING Template = &MRxSmbAll8dot3Files;
|
||
ULONG DirectoryNameLength,TemplateLength,AllocationLength;
|
||
PBYTE SmbFileName;
|
||
|
||
//the stuffer cannot handle the intricate logic here so we
|
||
//will have to preallocate for the name
|
||
|
||
DirectoryNameLength = DirectoryName->Length;
|
||
TemplateLength = Template->Length;
|
||
AllocationLength = sizeof(WCHAR) // backslash separator
|
||
+DirectoryNameLength
|
||
+TemplateLength;
|
||
RxDbgTrace(0, Dbg, (" --> d/t/dl/tl/al <%wZ><%wZ>%08lx/%08lx/%08lx!\n",
|
||
DirectoryName,Template,
|
||
DirectoryNameLength,TemplateLength,AllocationLength));
|
||
|
||
FindFirstPattern.Buffer = (PWCHAR)RxAllocatePoolWithTag( PagedPool,AllocationLength,'0SxR');
|
||
if (FindFirstPattern.Buffer==NULL) {
|
||
RxDbgTrace(0, Dbg, (" --> Couldn't get the findfind pattern buffer!\n"));
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FINALLY;
|
||
}
|
||
|
||
SmbFileName = (PBYTE)FindFirstPattern.Buffer;
|
||
RtlCopyMemory(SmbFileName,DirectoryName->Buffer,DirectoryNameLength);
|
||
SmbFileName += DirectoryNameLength;
|
||
if (*((PWCHAR)(SmbFileName-sizeof(WCHAR))) != L'\\') {
|
||
*((PWCHAR)SmbFileName) = L'\\'; SmbFileName+= sizeof(WCHAR);
|
||
}
|
||
RtlCopyMemory(SmbFileName,Template->Buffer,TemplateLength);
|
||
SmbFileName += TemplateLength;
|
||
if ((TemplateLength == sizeof(WCHAR)) && (Template->Buffer[0]==DOS_STAR)) {
|
||
*((PWCHAR)SmbFileName) = L'.'; SmbFileName+= sizeof(WCHAR);
|
||
*((PWCHAR)SmbFileName) = L'*'; SmbFileName+= sizeof(WCHAR);
|
||
}
|
||
//*((PWCHAR)SmbFileName) = 0; SmbFileName+= sizeof(WCHAR); //trailing NULL;
|
||
//CODE.IMPROVEMENT we should potentially 8.3ize the string here
|
||
FindFirstPattern.Length = (USHORT)(SmbFileName - (PBYTE)FindFirstPattern.Buffer);
|
||
RxDbgTrace(0, Dbg, (" --> find1stpattern <%wZ>!\n",&FindFirstPattern));
|
||
} else {
|
||
ResumeKeyLength = sizeof(SMB_RESUME_KEY);
|
||
FindFirstPattern.Buffer = NULL;
|
||
FindFirstPattern.Length = 0;
|
||
}
|
||
|
||
|
||
ASSERT( StufferState );
|
||
|
||
COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_Never, SMB_COM_SEARCH,
|
||
SMB_REQUEST_SIZE(SEARCH),
|
||
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
|
||
);
|
||
|
||
MRxSmbDumpStufferState (1100,"SMB w/ core search before stuffing",StufferState);
|
||
|
||
MRxSmbStuffSMB (StufferState,
|
||
"0wwB4ywc!",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 2
|
||
3, // w _USHORT( MaxCount ); // Number of dir. entries to return
|
||
SearchAttributes, // w _USHORT( SearchAttributes );
|
||
SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 5
|
||
// UCHAR Buffer[1]; // Buffer containing:
|
||
&FindFirstPattern, // 4 //UCHAR BufferFormat1; // 0x04 -- ASCII
|
||
// //UCHAR FileName[]; // File name, may be null
|
||
0x05, // y //UCHAR BufferFormat2; // 0x05 -- Variable block
|
||
ResumeKeyLength, // w //USHORT ResumeKeyLength; // Length of resume key, may be 0
|
||
// c
|
||
ResumeKeyLength,OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey
|
||
);
|
||
|
||
|
||
MRxSmbDumpStufferState (700,"SMB w/ core search for checkempty after stuffing",StufferState);
|
||
//ASSERT(!"Now it's stuffed");
|
||
|
||
|
||
FINALLY:
|
||
if (FindFirstPattern.Buffer != NULL) {
|
||
RxFreePool(FindFirstPattern.Buffer);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbBuildCheckEmptyDirectory exiting.......st=%08lx\n",Status));
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
SmbPseExchangeStart_SetDeleteDisposition(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the start routine for SetDeleteDisposition and downlevel delete. This only thing that happens here
|
||
is that we check for an empty directory. On core, this is harder than you think. what we do is to try to get three
|
||
entries. if the directory is empty, we will get only two . and ..; since we do not know whether the server just terminated
|
||
early or whether those are the only two, we go again. we do this until either we get a name that is not . or .. or until
|
||
NO_MORE_FILES is returned. sigh..................
|
||
|
||
Arguments:
|
||
|
||
pExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
|
||
RxCaptureFcb; RxCaptureFobx;
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
||
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
||
|
||
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
|
||
ULONG SmbLength;
|
||
|
||
PAGED_CODE();
|
||
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_SetDeleteDisposition\n", 0 ));
|
||
|
||
ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);
|
||
|
||
ASSERT(!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
|
||
ASSERT (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey == NULL);
|
||
|
||
for (;;) {
|
||
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC')); //CODE.IMPROVEMENT do this in the buildroutine
|
||
|
||
Status = MRxSmbBuildCheckEmptyDirectory(StufferState);
|
||
SmbLength = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
|
||
if ( (Status == RX_MAP_STATUS(BUFFER_OVERFLOW))
|
||
|| (SmbLength>pServer->MaximumBufferSize) ){
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition - name too long\n", 0 ));
|
||
return(RX_MAP_STATUS(OBJECT_NAME_INVALID));
|
||
} else if ( Status != RX_MAP_STATUS(SUCCESS) ){
|
||
goto FINALLY;
|
||
}
|
||
|
||
Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_CORESEARCHFORCHECKEMPTY
|
||
);
|
||
//
|
||
// if success is returned with a resume key then we have to go again
|
||
|
||
if ( (Status == RX_MAP_STATUS(SUCCESS)) && (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey != NULL) ) continue;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// this is pretty strange. if it succeeds, then fail the empty check. similarly, if the search
|
||
// fails with the right status...succeeed the check. otherwise fail
|
||
|
||
FINALLY:
|
||
if (Status == RX_MAP_STATUS(SUCCESS)) {
|
||
Status = RX_MAP_STATUS(DIRECTORY_NOT_EMPTY);
|
||
} else if (Status == RX_MAP_STATUS(NO_MORE_FILES)) {
|
||
Status = RX_MAP_STATUS(SUCCESS);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_SetDeleteDisposition exit w %08lx\n", Status ));
|
||
return Status;
|
||
}
|
||
|
||
|
||
MRxSmbSetDeleteDisposition(
|
||
IN PRX_CONTEXT RxContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine does a delete for downlevel.
|
||
|
||
It is impossible to provide exact NTish semantics on a core server. So, all we do here is to ensure that
|
||
a directory is empty. The actual delete happens when on the last close.
|
||
|
||
|
||
Arguments:
|
||
|
||
RxContext - the RDBSS context
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
|
||
PUNICODE_STRING RemainingName;
|
||
RxCaptureFcb; RxCaptureFobx;
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbSetDeleteDisposition\n", 0 ));
|
||
|
||
ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY ) {
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition not a directory!\n"));
|
||
return(RX_MAP_STATUS(SUCCESS));
|
||
}
|
||
|
||
Status = SmbPseCreateOrdinaryExchange(RxContext,
|
||
capFobx->pSrvOpen->pVNetRoot,
|
||
SMBPSE_OE_FROM_FAKESETDELETEDISPOSITION,
|
||
SmbPseExchangeStart_SetDeleteDisposition,
|
||
&OrdinaryExchange
|
||
);
|
||
if (Status != STATUS_SUCCESS) {
|
||
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
|
||
return(Status);
|
||
}
|
||
|
||
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
|
||
|
||
ASSERT (Status != RX_MAP_STATUS(PENDING));
|
||
|
||
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition exit with status=%08lx\n", Status ));
|
||
return(Status);
|
||
|
||
}
|
||
|
||
|