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);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|