2025-04-27 07:49:33 -04:00

1032 lines
34 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
fileinfo.c
Abstract:
This module implements the mini redirector call down routines pertaining to retrieval/
update of file/directory/volume information.
--*/
#include "precomp.h"
#pragma hdrstop
#pragma warning(error:4101) // Unreferenced local variable
RXDT_DefineCategory(DIRCTRL);
#define Dbg (DEBUG_TRACE_DIRCTRL)
BOOLEAN MRxSmbBypassDownLevelRename = FALSE;
ULONG UnalignedDirEntrySideBufferSize = 16384;
//
// All T2Find requests to the remote server request the 32 bit resume key
// so SMB_RFIND_BUFFER2 is used instead of SMB_FIND_BUFFER2.
//
typedef struct _SMB_FIND_BUFFER2_WITH_RESUME {
_ULONG( ResumeKey );
SMB_FIND_BUFFER2;
} SMB_FIND_BUFFER2_WITH_RESUME;
typedef SMB_FIND_BUFFER2_WITH_RESUME SMB_UNALIGNED *PSMB_FIND_BUFFER2_WITH_RESUME;
LIST_ENTRY MRxSmbSideBuffersList = {NULL,NULL};
ULONG MRxSmbSideBuffersSpinLock = 0;
ULONG MRxSmbSideBuffersCount = 0;
ULONG MRxSmbSideBuffersSerialNumber = 0;
BOOLEAN MRxSmbLoudSideBuffers = FALSE;
typedef struct _SIDE_BUFFER {
LIST_ENTRY ListEntry;
PMRX_FCB Fcb;
PMRX_FOBX Fobx;
PMRX_SMB_FOBX smbFobx;
ULONG SerialNumber;
BYTE Buffer;
} SIDE_BUFFER, *PSIDE_BUFFER;
#if DBG
#define MRxSmbAllocateSideBuffer(a,b,c,d) __MRxSmbAllocateSideBuffer(a,b,c,d)
#else
#define MRxSmbAllocateSideBuffer(a,b,c,d) __MRxSmbAllocateSideBuffer(a,b,c)
#endif
VOID
__MRxSmbAllocateSideBuffer(
IN OUT PRX_CONTEXT RxContext,
IN OUT PMRX_SMB_FOBX smbFobx,
IN USHORT Setup
#if DBG
,IN PUNICODE_STRING smbtemplate
#endif
)
{
RxCaptureFcb;RxCaptureFobx;
PSIDE_BUFFER SideBuffer;
ULONG SideBufferSize = UnalignedDirEntrySideBufferSize+sizeof(SIDE_BUFFER);
ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
SideBuffer = (PSIDE_BUFFER)RxAllocatePoolWithTag(
PagedPool,
SideBufferSize,
MRXSMB_DIRCTL_POOLTAG);
if (SideBuffer==NULL) {
return;
}
ASSERT( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
SideBuffer->smbFobx = smbFobx;
SideBuffer->Fobx = capFobx;
SideBuffer->Fcb = capFcb;
smbFobx->Enumeration.UnalignedDirEntrySideBuffer = &SideBuffer->Buffer;
smbFobx->Enumeration.SerialNumber = SideBuffer->SerialNumber = InterlockedIncrement(&MRxSmbSideBuffersSerialNumber);
InterlockedIncrement(&MRxSmbSideBuffersCount);
if (MRxSmbSideBuffersList.Flink==NULL) {
InitializeListHead(&MRxSmbSideBuffersList);
}
ExAcquireFastMutexUnsafe(&MRxIfsSerializationMutex);
InsertTailList(&MRxSmbSideBuffersList,&SideBuffer->ListEntry);
ExReleaseFastMutexUnsafe(&MRxIfsSerializationMutex);
if (!MRxSmbLoudSideBuffers) return;
KdPrint(("Allocating side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s %wZ\n",
&SideBuffer->Buffer,
MRxSmbSideBuffersCount,
smbFobx,capFobx,capFobx->pSrvOpen,
&capFcb->AlreadyPrefixedName,
(Setup == TRANS2_FIND_FIRST2)?"First":"Next",
smbtemplate
));
}
VOID
MRxSmbDeallocateSideBuffer(
IN OUT PRX_CONTEXT RxContext,
IN OUT PMRX_SMB_FOBX smbFobx,
IN PSZ where
)
{
PSIDE_BUFFER SideBuffer;
RxCaptureFcb;RxCaptureFobx;
if( smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) return;
SideBuffer = CONTAINING_RECORD(smbFobx->Enumeration.UnalignedDirEntrySideBuffer,SIDE_BUFFER,Buffer);
if (MRxSmbLoudSideBuffers){
DbgPrint("D--------- side buffer %08lx %08lx %08lx %08lx %08lxon <%wZ> %s\n",
&SideBuffer->Buffer,
MRxSmbSideBuffersCount,
smbFobx,capFobx,capFobx->pSrvOpen,
&capFcb->AlreadyPrefixedName,
where
);
}
ASSERT(SideBuffer->Fobx == capFobx);
ASSERT(SideBuffer->Fcb == capFcb);
ASSERT(SideBuffer->smbFobx == smbFobx);
ASSERT(smbFobx->Enumeration.SerialNumber == SideBuffer->SerialNumber);
ExAcquireFastMutexUnsafe(&MRxIfsSerializationMutex);
InterlockedDecrement(&MRxSmbSideBuffersCount);
RemoveEntryList(&SideBuffer->ListEntry);
ExReleaseFastMutexUnsafe(&MRxIfsSerializationMutex);
RxFreePool(SideBuffer);
smbFobx->Enumeration.UnalignedDirEntrySideBuffer = NULL;
}
VOID
MRxSmbTranslateLanManFindBuffer(
PRX_CONTEXT RxContext,
PULONG PreviousReturnedEntry,
PBYTE ThisEntryInBuffer
)
{
RxCaptureFcb; RxCaptureFobx;
PSMBCEDB_SERVER_ENTRY pServerEntry;
PSMBCE_SERVER Server;
ULONG FileInformationClass = RxContext->Info.FileInformationClass;
PFILE_FULL_DIR_INFORMATION NtBuffer = (PFILE_FULL_DIR_INFORMATION)PreviousReturnedEntry;
PSMB_FIND_BUFFER2_WITH_RESUME SmbBuffer = (PSMB_FIND_BUFFER2_WITH_RESUME)ThisEntryInBuffer;
SMB_TIME Time;
SMB_DATE Date;
PAGED_CODE();
if (FileInformationClass==FileNamesInformation) { return; }
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
Server = &pServerEntry->Server;
SmbMoveTime (&Time, &SmbBuffer->CreationTime);
SmbMoveDate (&Date, &SmbBuffer->CreationDate);
NtBuffer->CreationTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
SmbMoveTime (&Time, &SmbBuffer->LastAccessTime);
SmbMoveDate (&Date, &SmbBuffer->LastAccessDate);
NtBuffer->LastAccessTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
SmbMoveTime (&Time, &SmbBuffer->LastWriteTime);
SmbMoveDate (&Date, &SmbBuffer->LastWriteDate);
NtBuffer->LastWriteTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
NtBuffer->ChangeTime.QuadPart = 0;
NtBuffer->EndOfFile.QuadPart = SmbGetUlong(&SmbBuffer->DataSize);
NtBuffer->AllocationSize.QuadPart = SmbGetUlong(&SmbBuffer->AllocationSize);
NtBuffer->FileAttributes = MRxSmbMapSmbAttributes(SmbBuffer->Attributes);
if ((FileInformationClass==FileFullDirectoryInformation)
|| (FileInformationClass==FileBothDirectoryInformation)) {
NtBuffer->EaSize = SmbGetUlong(&SmbBuffer->EaSize);
}
}
NTSTATUS
MrxSmbUnalignedDirEntryCopyTail(
IN OUT PRX_CONTEXT RxContext,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN OUT PVOID pBuffer,
IN OUT PULONG pLengthRemaining,
IN OUT PMRX_SMB_FOBX smbFobx
)
/*++
Routine Description:
This routine copies the data from the side buffer into the users buffer and adjusts the
lengths remaining appropriately. this is called either if the server doesn't do unicode (w95) OR
if the server does not promise to quadalign entries OR if the user's buffer is not quadaligned.
this routine can be entered after a T2 finishes or to copy the last entries from a previous T2. in the second case, the
pUnalignedDirEntrySideBuffer ptr will be null and it will go to acquire the correct pointer from the smbFobx.
this routine has the responsibility to free the sidebufferptr when it is exhausted.
Arguments:
RxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureFcb;
ULONG i,NameSizeInUnicode;
LONG LocalLengthRemaining; //signed arithmetic makes it easier
PULONG PreviousReturnedEntry;
ULONG FileNameLengthOffset = smbFobx->Enumeration.FileNameLengthOffset;
ULONG FileNameOffset = smbFobx->Enumeration.FileNameOffset;
PBYTE UnalignedDirEntrySideBuffer = smbFobx->Enumeration.UnalignedDirEntrySideBuffer;
BOOLEAN IsUnicode = smbFobx->Enumeration.IsUnicode;
BOOLEAN IsNonNtT2Find = smbFobx->Enumeration.IsNonNtT2Find;
PMRX_SMB_DIRECTORY_RESUME_INFO ResumeInfo = smbFobx->Enumeration.ResumeInfo;
ULONG FilesReturned = smbFobx->Enumeration.FilesReturned;
ULONG EntryOffset = smbFobx->Enumeration.EntryOffset;
ULONG ReturnedEntryOffset;// = smbFobx->Enumeration.ReturnedEntryOffset;
BOOLEAN EndOfSearchReached = smbFobx->Enumeration.EndOfSearchReached;
ULONG TotalDataBytesReturned = smbFobx->Enumeration.TotalDataBytesReturned;
BOOLEAN FilterFailure;
LocalLengthRemaining = (LONG)(*pLengthRemaining);
for (i=ReturnedEntryOffset=0;;) {
ULONG FileNameLength,ThisEntrySize; PCHAR FileNameBuffer;
UNICODE_STRING ReturnedFileName;
OEM_STRING FileName;
NTSTATUS StringStatus;
BOOLEAN TwoExtraBytes = TRUE;
ULONG resumekey,NextEntryOffsetinBuffer;
PULONG PreviousPreviousReturnedEntry;
PBYTE ThisEntryInBuffer = UnalignedDirEntrySideBuffer+EntryOffset;
// don't EVER let yourself get past the data returned...servers return funny stuff.......
if (EntryOffset>=TotalDataBytesReturned){
DbgPrint("limits1: %08lx %08lx \n",EntryOffset+NextEntryOffsetinBuffer,TotalDataBytesReturned);
FilterFailure = TRUE;
FilesReturned = i; //we're done with this buffer........
break;
}
if (!IsNonNtT2Find) {
FileNameLength = SmbGetUlong(ThisEntryInBuffer+FileNameLengthOffset);
FileNameBuffer = ThisEntryInBuffer+FileNameOffset;
resumekey = SmbGetUlong(ThisEntryInBuffer
+FIELD_OFFSET(FILE_FULL_DIR_INFORMATION,FileIndex));
NextEntryOffsetinBuffer = SmbGetUlong(ThisEntryInBuffer);
} else {
FileNameLength = *(ThisEntryInBuffer
+FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileNameLength));
FileNameBuffer = ThisEntryInBuffer
+FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0]);
resumekey = SmbGetUlong(ThisEntryInBuffer+
+FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,ResumeKey));
NextEntryOffsetinBuffer = FIELD_OFFSET(SMB_FIND_BUFFER2_WITH_RESUME,FileName[0])
+ FileNameLength + 1; //the +1 is for the null..we could have said Filename{1]
PreviousPreviousReturnedEntry = PreviousReturnedEntry; //save this for rollback on filterfail
}
// some servers lie about how many entries were returned and/or send partial entries
if (EntryOffset+NextEntryOffsetinBuffer>TotalDataBytesReturned){
DbgPrint("limits: %08lx %08lx \n",EntryOffset+NextEntryOffsetinBuffer,TotalDataBytesReturned);
FilterFailure = TRUE;
FilesReturned = i; //we're done with this buffer........
break;
}
FileName.Buffer = FileNameBuffer;
FileName.Length = (USHORT)FileNameLength;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: EO,REO=%08lx,%08lx\n",
EntryOffset,ReturnedEntryOffset));
//check to see if this entry will fit
if (IsUnicode) {
NameSizeInUnicode = FileNameLength;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %wZ\n",
FileNameLength,NameSizeInUnicode,&FileName));
} else {
NameSizeInUnicode = RtlxOemStringToUnicodeSize(&FileName)-sizeof(WCHAR);
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: length=%08lx/%08lx, name = %.*s\n",
FileNameLength,NameSizeInUnicode,FileNameLength,FileNameBuffer));
}
ThisEntrySize = FileNameOffset+NameSizeInUnicode;
if (((LONG)ThisEntrySize)>LocalLengthRemaining) {
break;
}
if (((LONG)ThisEntrySize)>LocalLengthRemaining-(LONG)sizeof(WCHAR)) {
TwoExtraBytes = FALSE;
}
ThisEntrySize = LongAlign(ThisEntrySize);
PreviousReturnedEntry = (PULONG)(((PBYTE)pBuffer)+ReturnedEntryOffset);
//now make sure that the next entry is quadaligned....we know that it's longaligned
if (!IsPtrQuadAligned((ULONG)(PreviousReturnedEntry)+ThisEntrySize) ){
ThisEntrySize += sizeof(ULONG);
}
if (i!=0) {
ASSERT(IsPtrQuadAligned(PreviousReturnedEntry));
}
if (!IsNonNtT2Find) {
//copy everything in the entry up to but not including the name info
RtlCopyMemory(PreviousReturnedEntry,UnalignedDirEntrySideBuffer+EntryOffset,FileNameOffset);
} else {
IF_DEBUG {
RtlZeroMemory(PreviousReturnedEntry,FileNameOffset);
}
}
// store the length of this entry and the size of the name...if this is the last
// entry returned, then the offset field will be cleared later
*PreviousReturnedEntry = ThisEntrySize;
*((PULONG)(((PBYTE)PreviousReturnedEntry)+FileNameLengthOffset)) = NameSizeInUnicode;
//copy in the name .........this is made difficult by the oem-->unicode routine that
// requires space for a NULL!
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: REO/buf/pentry=%08lx/%08lx/%08lx\n",
pBuffer,ReturnedEntryOffset,PreviousReturnedEntry));
ReturnedFileName.Buffer = (PWCH)(((PBYTE)PreviousReturnedEntry)+FileNameOffset);
if (!IsUnicode) {
if (TwoExtraBytes) {
ReturnedFileName.MaximumLength = sizeof(WCHAR)+(USHORT)NameSizeInUnicode;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
StringStatus = RtlOemStringToUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
} else {
OEM_STRING LastChar;
UNICODE_STRING LastCharInUnicode;
WCHAR UnicodeCharBuffer[2];
ReturnedFileName.MaximumLength = (USHORT)NameSizeInUnicode;
FileName.Length -= 1;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: filenamebuf,length=%08lx/%08lx\n",
ReturnedFileName.Buffer,ReturnedFileName.MaximumLength));
StringStatus = RtlOemStringToUnicodeString(&ReturnedFileName,&FileName,FALSE); //false means don;t allocate
ASSERT(StringStatus==STATUS_SUCCESS);
LastChar.Buffer = FileName.Buffer+FileName.Length;
LastChar.Length = 1;
LastCharInUnicode.Buffer = (PWCH)&UnicodeCharBuffer;
LastCharInUnicode.MaximumLength = sizeof(UnicodeCharBuffer);
StringStatus = RtlOemStringToUnicodeString(&LastCharInUnicode,&LastChar,FALSE); //false means don;t allocate
*((PWCH)(((PBYTE)ReturnedFileName.Buffer)+ReturnedFileName.Length)) = UnicodeCharBuffer[0];
}
ASSERT(StringStatus==STATUS_SUCCESS);
//spread out the shortname which has also been returned in ascii
if ((FileInformationClass == FileBothDirectoryInformation) && !IsNonNtT2Find) {
PFILE_BOTH_DIR_INFORMATION BothInfo = (PFILE_BOTH_DIR_INFORMATION)PreviousReturnedEntry;
PBYTE NameAsSingleBytes = (PBYTE)(&BothInfo->ShortName[0]);
ULONG ShortNameLength = BothInfo->ShortNameLength;
if (ShortNameLength != 0) {
ULONG i;
for (i=ShortNameLength;;) {
i--;
BothInfo->ShortName[i] = *(NameAsSingleBytes+i);
if (i==0) {break;}
}
}
ShortNameLength += ShortNameLength; //convert to UNICODE length;
BothInfo->ShortNameLength = (CHAR)ShortNameLength;
IF_DEBUG {
UNICODE_STRING LastName;
LastName.Buffer = (PWCHAR)NameAsSingleBytes;
LastName.Length = (USHORT)ShortNameLength;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodeshortnamename = %wZ\n", &LastName));
}
}
} else {
//here, it's already unicode.....just copy the bytes
RtlCopyMemory(ReturnedFileName.Buffer,FileName.Buffer,FileName.Length);
}
IF_DEBUG {
UNICODE_STRING LastName;
LastName.Buffer = ReturnedFileName.Buffer;
LastName.Length = (USHORT)NameSizeInUnicode;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: unicodename = %wZ\n", &LastName));
}
//now...setup to resume based on this entry
if (ResumeInfo != NULL) {
PREQ_FIND_NEXT2 pFindNext2Request = &ResumeInfo->FindNext2_Request;
pFindNext2Request->ResumeKey = resumekey;
RxDbgTrace(0,Dbg,("MRxSmbQueryDirectoryWin95: resumekey = %08lx\n", resumekey));
RtlCopyMemory(&pFindNext2Request->Buffer[0],FileNameBuffer,FileNameLength);
//buffer is a UCHAR...not WCHAR
if (IsUnicode) {
// In the case of UNICODE strings an additional NULL is required ( WCHAR NULL )
pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
pFindNext2Request->Buffer[FileNameLength + 1] = 0; //nullterminated
smbFobx->Enumeration.ResumeInfo->ParametersLength
= &pFindNext2Request->Buffer[FileNameLength+2] - (PBYTE)pFindNext2Request;
} else {
pFindNext2Request->Buffer[FileNameLength] = 0; //nullterminated
smbFobx->Enumeration.ResumeInfo->ParametersLength
= &pFindNext2Request->Buffer[FileNameLength+1] - (PBYTE)pFindNext2Request;
}
}
//at this point, we have copied the name and the resume key. BUT, for nonnt we have to
//filter the names so we still may have to roll back
if (!IsNonNtT2Find) {
FilterFailure = FALSE;
} else {
FilterFailure = FALSE;
if (smbFobx->Enumeration.WildCardsFound ) {
RxCaptureFobx; //do this here so it's not on the NT path
FilterFailure = !FsRtlIsNameInExpression( &capFobx->UnicodeQueryTemplate,
&ReturnedFileName, TRUE, NULL );
}
if (!FilterFailure) {
//DbgPrint("Passed Filter %wZ\n",&ReturnedFileName);
MRxSmbTranslateLanManFindBuffer(RxContext,PreviousReturnedEntry,ThisEntryInBuffer);
} else {
PreviousReturnedEntry = PreviousPreviousReturnedEntry; //rollback on filterfail
}
}
if (!FilterFailure) {
if (FALSE) {
IF_DEBUG {
UNICODE_STRING LastName;
LastName.Buffer = ReturnedFileName.Buffer;
LastName.Length = (USHORT)NameSizeInUnicode;
DbgPrint("Adding %wZ\n",&LastName);
}
}
LocalLengthRemaining -= ThisEntrySize;
i++;
ReturnedEntryOffset += ThisEntrySize;
} else {
FilesReturned--;
}
EntryOffset += NextEntryOffsetinBuffer;
if ((i>=FilesReturned)
||(LocalLengthRemaining<0)
|| (RxContext->QueryDirectory.ReturnSingleEntry&&(i>0)) ) {
break;
}
}
//ASSERT(!IsNonNtT2Find);
if (i==0) {
Status = FilterFailure?STATUS_MORE_PROCESSING_REQUIRED:STATUS_BUFFER_OVERFLOW;
} else {
*PreviousReturnedEntry = 0;
}
if (LocalLengthRemaining <= 0) {
*pLengthRemaining = 0;
} else {
*pLengthRemaining = (ULONG)LocalLengthRemaining;
}
if (i>=FilesReturned) {
RxLog(("sidebufdealloc %lx %lx\n",RxContext,smbFobx));
MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Tail");
if (EndOfSearchReached) {
//smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN;
//we will close the search handle when the user's handle closes
smbFobx->Enumeration.ErrorStatus = STATUS_NO_MORE_FILES;
}
} else {
//set up to resume here
ASSERT(smbFobx->Enumeration.UnalignedDirEntrySideBuffer == UnalignedDirEntrySideBuffer);
smbFobx->Enumeration.EntryOffset = EntryOffset;
smbFobx->Enumeration.FilesReturned = FilesReturned - i;
}
return(Status);
}
NTSTATUS
MRxIfsQueryDirectory(
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine does a directory query. Only the NT-->NT path is implemented.
Arguments:
RxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
RxCaptureFcb;
RxCaptureFobx;
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
FILE_INFORMATION_CLASS FileInformationClass;
PVOID Buffer;
PULONG pLengthRemaining;
USHORT SmbFileInfoLevel;
BOOLEAN DirEntriesAreUaligned = FALSE;
BOOLEAN IsUnicode = TRUE;
USHORT SearchFlags = SMB_FIND_CLOSE_AT_EOS|SMB_FIND_RETURN_RESUME_KEYS;
#if DBG
UNICODE_STRING smbtemplate = {0,0,NULL};
#endif
TURN_BACK_ASYNCHRONOUS_OPERATIONS();
FileInformationClass = RxContext->Info.FileInformationClass;
Buffer = RxContext->Info.Buffer;
pLengthRemaining = &RxContext->Info.LengthRemaining;
ASSERT (*pLengthRemaining<0x10000);
RxDbgTrace(+1, Dbg, ("MRxSmbQueryDirectory: directory=<%wZ>\n",
&(capFcb->AlreadyPrefixedName)
));
#define __GET_NAME_PARAMS_FOR_TYPE(___type___) { \
smbFobx->Enumeration.FileNameOffset = (USHORT)FIELD_OFFSET(___type___,FileName[0]); \
smbFobx->Enumeration.FileNameLengthOffset = (USHORT)FIELD_OFFSET(___type___,FileNameLength); \
}
switch (FileInformationClass) {
case FileDirectoryInformation:
SmbFileInfoLevel = SMB_FIND_FILE_DIRECTORY_INFO;
__GET_NAME_PARAMS_FOR_TYPE(FILE_DIRECTORY_INFORMATION);
break;
case FileFullDirectoryInformation:
SmbFileInfoLevel = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
__GET_NAME_PARAMS_FOR_TYPE(FILE_FULL_DIR_INFORMATION);
break;
case FileBothDirectoryInformation:
SmbFileInfoLevel = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
__GET_NAME_PARAMS_FOR_TYPE(FILE_BOTH_DIR_INFORMATION);
break;
case FileNamesInformation:
SmbFileInfoLevel = SMB_FIND_FILE_NAMES_INFO;
__GET_NAME_PARAMS_FOR_TYPE(FILE_NAMES_INFORMATION);
break;
default:
RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Invalid FS information class\n"));
Status = STATUS_INVALID_PARAMETER;
goto FINALLY;
}
#if DBG
if (MRxSmbLoudSideBuffers) {
SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_LOUD_FINALIZE);
}
#endif
//
// force the core operation
//
Status = MRxSmbCoreInformation(RxContext,
(ULONG)SmbFileInfoLevel,
Buffer,
pLengthRemaining,
SMBPSE_OE_FROM_QUERYDIRECTORY
);
return Status;
FINALLY:
if (!NT_SUCCESS(Status)) {
RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: Failed .. returning %lx\n",Status));
smbFobx->Enumeration.ErrorStatus = Status; //keep returning this
MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"ErrOut");
if (smbFobx->Enumeration.ResumeInfo != NULL)
{
RxFreePool(smbFobx->Enumeration.ResumeInfo);
smbFobx->Enumeration.ResumeInfo = NULL;
}
}
RxDbgTraceUnIndent(-1,Dbg);
return Status;
}
RXDT_DefineCategory(VOLINFO);
#undef Dbg
#define Dbg (DEBUG_TRACE_VOLINFO)
NTSTATUS
MRxIfsQueryVolumeInformation(
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine queries the volume information
Arguments:
pRxContext - the RDBSS context
FsInformationClass - the kind of Fs information desired.
pBuffer - the buffer for copying the information
pBufferLength - the buffer length ( set to buffer length on input and set
to the remaining length on output)
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
RxCaptureFcb;
RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen;
FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
PVOID pBuffer = RxContext->Info.Buffer;
PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
PSMBCEDB_SERVER_ENTRY pServerEntry;
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
if ( FsInformationClass == FileFsDeviceInformation )
{
PFILE_FS_DEVICE_INFORMATION UsersBuffer = (PFILE_FS_DEVICE_INFORMATION)pBuffer;
PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
UsersBuffer->Characteristics = FILE_REMOTE_DEVICE;
UsersBuffer->DeviceType = NetRoot->DeviceType;
*pLengthRemaining -= (sizeof(FILE_FS_DEVICE_INFORMATION));
RxDbgTrace( 0, Dbg, ("MRxSmbQueryVolumeInformation: devinfo .. returning\n"));
return STATUS_SUCCESS;
}
if (capFobx != NULL)
{
SrvOpen = capFobx->pSrvOpen;
smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
}
else
{
return STATUS_INVALID_PARAMETER;
}
TURN_BACK_ASYNCHRONOUS_OPERATIONS();
Status = MRxSmbCoreInformation(RxContext,
(ULONG)FsInformationClass,
pBuffer,
pLengthRemaining,
SMBPSE_OE_FROM_QUERYVOLUMEINFO
);
return Status;
}
NTSTATUS
MRxIfsSetVolumeInformation(
IN OUT PRX_CONTEXT pRxContext
)
/*++
Routine Description:
This routine sets the volume information
Arguments:
pRxContext - the RDBSS context
FsInformationClass - the kind of Fs information desired.
pBuffer - the buffer for copying the information
BufferLength - the buffer length
Return Value:
NTSTATUS - The return status for the operation
--*/
{
return STATUS_NOT_IMPLEMENTED;
}
RXDT_DefineCategory(FILEINFO);
#undef Dbg
#define Dbg (DEBUG_TRACE_FILEINFO)
NTSTATUS
MRxIfsQueryFileInformation(
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine does a query file info. Only the NT-->NT path is implemented.
The NT-->NT path works by just remoting the call basically without further ado.
Arguments:
RxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
RxCaptureFcb;
RxCaptureFobx;
FILE_INFORMATION_CLASS FileInformationClass;
PVOID pBuffer;
PULONG pLengthRemaining;
PSMBCEDB_SERVER_ENTRY pServerEntry;
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
USHORT SmbFileInfoLevel;
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
FileInformationClass = RxContext->Info.FileInformationClass;
pBuffer = RxContext->Info.Buffer;
pLengthRemaining = &RxContext->Info.LengthRemaining;
RxDbgTrace(+1, Dbg, ("MRxSmbQueryFileInformation: class=%08lx\n",FileInformationClass));
if ( FileInformationClass == FileInternalInformation ) {
PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pBuffer;
//
// Note: We use the address of the FCB to determine the
// index number of the file. If we have to maintain persistance between
// file opens for this request, then we might have to do something
// like checksuming the reserved fields on a FUNIQUE SMB response.
//
UsersBuffer->IndexNumber.LowPart = (ULONG )capFcb;
UsersBuffer->IndexNumber.LowPart = (ULONG)capFcb;
UsersBuffer->IndexNumber.HighPart = 0;
Status = STATUS_SUCCESS;
*pLengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
RxDbgTrace(-1, Dbg, ("MRxSmbQueryFileInformation: internalinfo .. returning\n"));
return STATUS_SUCCESS;
}
TURN_BACK_ASYNCHRONOUS_OPERATIONS();
ASSERT (*pLengthRemaining<0x10000);
switch (FileInformationClass) {
case FilePipeLocalInformation:
case FilePipeInformation:
case FilePipeRemoteInformation:
//
// N.B. No pipe support in this example mini-rdr
//
return STATUS_NOT_IMPLEMENTED;
case FileBasicInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_BASIC_INFO;
break;
case FileStandardInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_STANDARD_INFO;
break;
case FileEaInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_EA_INFO;
break;
case FileAllocationInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_ALLOCATION_INFO;
break;
case FileEndOfFileInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_END_OF_FILEINFO;
break;
case FileAlternateNameInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_ALT_NAME_INFO;
break;
case FileStreamInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_STREAM_INFO;
break;
case FileCompressionInformation:
SmbFileInfoLevel = SMB_QUERY_FILE_COMPRESSION_INFO;
break;
default:
RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Invalid FS information class\n"));
Status = STATUS_INVALID_PARAMETER;
goto FINALLY;
}
Status = MRxSmbCoreInformation(RxContext,
(ULONG)SmbFileInfoLevel,
pBuffer,
pLengthRemaining,
SMBPSE_OE_FROM_QUERYFILEINFO
);
FINALLY:
if (!NT_SUCCESS(Status)) {
RxDbgTrace( 0, Dbg, ("MRxSmbQueryFile: Failed .. returning %lx\n",Status));
}
RxDbgTraceUnIndent(-1,Dbg);
return Status;
}
typedef enum _INTERESTING_SFI_FOLLOWONS {
SFI_FOLLOWON_NOTHING,
SFI_FOLLOWON_DISPOSITION_SENT
} INTERESTING_SFI_FOLLOWONS;
NTSTATUS
MRxIfsSetFileInformation(
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine does a set file info. Only the NT-->NT path is implemented.
The NT-->NT path works by just remoting the call basically without further ado.
Arguments:
RxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
RxCaptureFcb;
RxCaptureFobx;
FILE_INFORMATION_CLASS FileInformationClass;
PVOID pBuffer;
ULONG BufferLength;
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
PSMBCEDB_SERVER_ENTRY pServerEntry;
USHORT SmbFileInfoLevel;
INTERESTING_SFI_FOLLOWONS FollowOn = SFI_FOLLOWON_NOTHING;
TURN_BACK_ASYNCHRONOUS_OPERATIONS();
FileInformationClass = RxContext->Info.FileInformationClass;
pBuffer = RxContext->Info.Buffer;
BufferLength = RxContext->Info.Length;
RxDbgTrace(+1, Dbg, ("MRxSmbSetFile: Class %08lx size %08lx\n",FileInformationClass,BufferLength));
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
switch (FileInformationClass) {
case FileBasicInformation:
SmbFileInfoLevel = SMB_SET_FILE_BASIC_INFO;
break;
case FileDispositionInformation:
SmbFileInfoLevel = SMB_SET_FILE_DISPOSITION_INFO;
FollowOn = SFI_FOLLOWON_DISPOSITION_SENT;
break;
case FileAllocationInformation:
SmbFileInfoLevel = SMB_SET_FILE_ALLOCATION_INFO;
break;
case FileEndOfFileInformation:
SmbFileInfoLevel = SMB_SET_FILE_END_OF_FILE_INFO;
break;
case FileRenameInformation:
if (!MRxSmbBypassDownLevelRename) {
Status = MRxIfsRename(RxContext,FileInformationClass,pBuffer,BufferLength);
goto FINALLY;
}
default:
RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Invalid FS information class\n"));
Status = STATUS_INVALID_PARAMETER;
goto FINALLY;
}
Status = MRxSmbCoreInformation(RxContext,
FileInformationClass,
pBuffer,
&BufferLength,
SMBPSE_OE_FROM_SETFILEINFO
);
FINALLY:
if (!NT_SUCCESS(Status)) {
RxDbgTrace( 0, Dbg, ("MRxSmbSetFile: Failed .. returning %lx\n",Status));
}
RxDbgTraceUnIndent(-1,Dbg);
return Status;
}
NTSTATUS
MRxIfsSetFileInformationAtCleanup(
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e.
it doesn't generate it). we are doing the same..........
Arguments:
pRxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
return STATUS_SUCCESS;
}