mirror of https://github.com/tongzx/nt5src
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.
2729 lines
78 KiB
2729 lines
78 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
FileInfo.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the File Information routines for Rx called by
|
|
the dispatch driver.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLinn] 5-oct-94
|
|
|
|
Revision History:
|
|
|
|
Balan Sethu Raman 15-May-95 -- reworked to fit in pipe FSCTL's
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_FILEINFO)
|
|
|
|
NTSTATUS
|
|
RxQueryBasicInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryStandardInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryInternalInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_INTERNAL_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryEaInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_EA_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryPositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_POSITION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryAlternateNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryCompressedInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_COMPRESSION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryPipeInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PVOID pPipeInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetBasicInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetDispositionInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetRenameInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetPositionInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetAllocationInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetEndOfFileInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetPipeInfo(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetSimpleInfo(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RxCommonQueryInformation)
|
|
#pragma alloc_text(PAGE, RxCommonSetInformation)
|
|
#pragma alloc_text(PAGE, RxSetAllocationInfo)
|
|
#pragma alloc_text(PAGE, RxQueryBasicInfo)
|
|
#pragma alloc_text(PAGE, RxQueryEaInfo)
|
|
#pragma alloc_text(PAGE, RxQueryInternalInfo)
|
|
#pragma alloc_text(PAGE, RxQueryNameInfo)
|
|
#pragma alloc_text(PAGE, RxQueryAlternateNameInfo)
|
|
#pragma alloc_text(PAGE, RxQueryPositionInfo)
|
|
#pragma alloc_text(PAGE, RxQueryStandardInfo)
|
|
#pragma alloc_text(PAGE, RxQueryPipeInfo)
|
|
#pragma alloc_text(PAGE, RxSetBasicInfo)
|
|
#pragma alloc_text(PAGE, RxSetDispositionInfo)
|
|
#pragma alloc_text(PAGE, RxSetEndOfFileInfo)
|
|
#pragma alloc_text(PAGE, RxSetPositionInfo)
|
|
#pragma alloc_text(PAGE, RxSetRenameInfo)
|
|
#pragma alloc_text(PAGE, RxSetPipeInfo)
|
|
#pragma alloc_text(PAGE, RxSetSimpleInfo)
|
|
#pragma alloc_text(PAGE, RxConjureOriginalName)
|
|
#pragma alloc_text(PAGE, RxQueryCompressedInfo)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
RxpSetInfoMiniRdr(
|
|
PRX_CONTEXT RxContext,
|
|
FILE_INFORMATION_CLASS FileInformationClass)
|
|
{
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
|
|
NTSTATUS Status;
|
|
|
|
RxContext->Info.FileInformationClass = FileInformationClass;
|
|
RxContext->Info.Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
RxContext->Info.Length = capPARAMS->Parameters.SetFile.Length;
|
|
MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfo,(RxContext));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxpQueryInfoMiniRdr(
|
|
PRX_CONTEXT RxContext,
|
|
FILE_INFORMATION_CLASS InformationClass,
|
|
PVOID Buffer)
|
|
{
|
|
RxCaptureFcb;
|
|
|
|
NTSTATUS Status;
|
|
|
|
RxContext->Info.FileInformationClass = InformationClass;
|
|
RxContext->Info.Buffer = Buffer;
|
|
|
|
MINIRDR_CALL(
|
|
Status,
|
|
RxContext,
|
|
capFcb->MRxDispatch,
|
|
MRxQueryFileInfo,
|
|
(RxContext));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCommonQueryInformation ( RXCOMMON_SIGNATURE )
|
|
/*++
|
|
Routine Description:
|
|
|
|
This is the common routine for querying file information called by both
|
|
the fsd and fsp threads.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the Irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|
PVOID Buffer = NULL;
|
|
FILE_INFORMATION_CLASS FileInformationClass = capPARAMS->Parameters.QueryFile.FileInformationClass;
|
|
|
|
BOOLEAN FcbAcquired = FALSE;
|
|
BOOLEAN PostIrp = FALSE;
|
|
|
|
PFILE_ALL_INFORMATION AllInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxCommonQueryInformation...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|
RxContext, capFobx, capFcb));
|
|
RxDbgTrace( 0, Dbg, (" Buffer %08lx Length %08lx FileInfoClass %08lx\n",
|
|
capReqPacket->AssociatedIrp.SystemBuffer,
|
|
capPARAMS->Parameters.QueryFile.Length,
|
|
capPARAMS->Parameters.QueryFile.FileInformationClass
|
|
));
|
|
RxLog(("QueryFileInfo %lx %lx %lx\n",RxContext,capFcb,capFobx));
|
|
RxWmiLog(LOG,
|
|
RxCommonQueryInformation_1,
|
|
LOGPTR(RxContext)
|
|
LOGPTR(capFcb)
|
|
LOGPTR(capFobx));
|
|
RxLog((" alsoqfi %lx %lx %ld\n",
|
|
capReqPacket->AssociatedIrp.SystemBuffer,
|
|
capPARAMS->Parameters.QueryFile.Length,
|
|
capPARAMS->Parameters.QueryFile.FileInformationClass
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxCommonQueryInformation_2,
|
|
LOGPTR(capReqPacket->AssociatedIrp.SystemBuffer)
|
|
LOGULONG(capPARAMS->Parameters.QueryFile.Length)
|
|
LOGULONG(capPARAMS->Parameters.QueryFile.FileInformationClass));
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length;
|
|
|
|
try {
|
|
// Obtain the Request packet's(user's) buffer
|
|
Buffer = RxMapSystemBuffer(RxContext);
|
|
|
|
if (Buffer == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
try_return(Status);
|
|
}
|
|
// Zero the buffer
|
|
RtlZeroMemory(
|
|
Buffer,
|
|
RxContext->Info.LengthRemaining);
|
|
|
|
// Case on the type of open we're dealing with
|
|
switch (TypeOfOpen) {
|
|
case RDBSS_NTC_STORAGE_TYPE_FILE:
|
|
case RDBSS_NTC_STORAGE_TYPE_UNKNOWN:
|
|
case RDBSS_NTC_STORAGE_TYPE_DIRECTORY:
|
|
{
|
|
// Acquire shared access to the fcb, except for a paging file
|
|
// in order to avoid deadlocks with Mm.
|
|
if (!FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
|
|
if (FileInformationClass != FileNameInformation) {
|
|
|
|
// If this is FileCompressedFileSize, we need the Fcb
|
|
// exclusive.
|
|
if (FileInformationClass != FileCompressionInformation) {
|
|
Status = RxAcquireSharedFcb(RxContext,capFcb);
|
|
} else {
|
|
Status = RxAcquireExclusiveFcb( RxContext, capFcb );
|
|
}
|
|
|
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|
RxDbgTrace(0, Dbg, ("Cannot acquire Fcb\n", 0));
|
|
try_return( PostIrp = TRUE );
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
try_return(PostIrp = FALSE);
|
|
}
|
|
|
|
FcbAcquired = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Based on the information class, call down to the minirdr
|
|
// we either complete or we post
|
|
|
|
switch (FileInformationClass) {
|
|
|
|
case FileAllInformation:
|
|
|
|
//
|
|
// For the all information class we'll typecast a local
|
|
// pointer to the output buffer and then call the
|
|
// individual routines to fill in the buffer.
|
|
//
|
|
|
|
AllInfo = Buffer;
|
|
|
|
// can't rely on QueryXXInfo functions to calculate LengthRemaining due to
|
|
// possible allignment issues
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, BasicInformation);
|
|
|
|
Status = RxQueryBasicInfo( RxContext, &AllInfo->BasicInformation );
|
|
if (Status!=STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, StandardInformation);
|
|
|
|
Status = RxQueryStandardInfo( RxContext, &AllInfo->StandardInformation );
|
|
if (Status!=STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, InternalInformation);
|
|
|
|
Status = RxQueryInternalInfo( RxContext, &AllInfo->InternalInformation );
|
|
if (Status!=STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, EaInformation);
|
|
|
|
Status = RxQueryEaInfo( RxContext, &AllInfo->EaInformation );
|
|
if (Status!=STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, PositionInformation);
|
|
|
|
Status = RxQueryPositionInfo( RxContext, &AllInfo->PositionInformation );
|
|
if (Status!=STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)capPARAMS->Parameters.QueryFile.Length
|
|
- FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation);
|
|
|
|
//QueryNameInfo could return buffer-overflow!!!
|
|
Status = RxQueryNameInfo( RxContext, &AllInfo->NameInformation );
|
|
break;
|
|
|
|
case FileBasicInformation:
|
|
|
|
Status = RxQueryBasicInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileStandardInformation:
|
|
|
|
Status = RxQueryStandardInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileInternalInformation:
|
|
|
|
Status = RxQueryInternalInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileEaInformation:
|
|
|
|
Status = RxQueryEaInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
Status = RxQueryPositionInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileNameInformation:
|
|
|
|
Status = RxQueryNameInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileAlternateNameInformation:
|
|
|
|
Status = RxQueryAlternateNameInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FileCompressionInformation:
|
|
|
|
Status = RxQueryCompressedInfo( RxContext, Buffer );
|
|
break;
|
|
|
|
case FilePipeInformation:
|
|
case FilePipeLocalInformation:
|
|
case FilePipeRemoteInformation:
|
|
|
|
Status = RxQueryPipeInfo( RxContext, Buffer);
|
|
break;
|
|
|
|
default:
|
|
//anything that we don't understand, we just remote
|
|
RxContext->StoredStatus = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileInformationClass,
|
|
Buffer);
|
|
|
|
Status = RxContext->StoredStatus;
|
|
break;
|
|
}
|
|
|
|
// If we overflowed the buffer, set the length to 0 and change the
|
|
// status to RxStatus(BUFFER_OVERFLOW).
|
|
if ( RxContext->Info.LengthRemaining < 0 ) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
RxContext->Info.LengthRemaining = capPARAMS->Parameters.QueryFile.Length;
|
|
}
|
|
|
|
// Set the information field to the number of bytes actually filled in
|
|
// and then complete the request LARRY DOES THIS UNDER "!NT_ERROR"
|
|
capReqPacket->IoStatus.Information = capPARAMS->Parameters.QueryFile.Length
|
|
- RxContext->Info.LengthRemaining;
|
|
}
|
|
break;
|
|
case RDBSS_NTC_MAILSLOT:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
default:
|
|
RxDbgTrace(0,Dbg,("RxCommonQueryInformation: Illegal Type of Open = %08lx\n", TypeOfOpen));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
try_exit:
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(PostIrp || RxContext->PostRequest)) {
|
|
Status = RxFsdPostRequest( RxContext );
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugUnwind( RxCommonQueryInformation );
|
|
|
|
if (FcbAcquired)
|
|
{
|
|
RxReleaseFcb( RxContext, capFcb );
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxCommonQueryInformation -> %08lx\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCommonSetInformation ( RXCOMMON_SIGNATURE )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common routine for setting file information called by both
|
|
the fsd and fsp threads.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the Irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|
PNET_ROOT NetRoot = (PNET_ROOT)capFcb->pNetRoot;
|
|
FILE_INFORMATION_CLASS FileInformationClass = capPARAMS->Parameters.SetFile.FileInformationClass;
|
|
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|
BOOLEAN FcbAcquired = FALSE;
|
|
BOOLEAN NetRootTableLockAcquired = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxCommonSetInformation...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|
RxContext, capFobx, capFcb));
|
|
RxDbgTrace( 0, Dbg, (" Buffer %08lx Length %08lx FileInfoClass %08lx Replace %08lx\n",
|
|
capReqPacket->AssociatedIrp.SystemBuffer,
|
|
capPARAMS->Parameters.QueryFile.Length,
|
|
capPARAMS->Parameters.QueryFile.FileInformationClass,
|
|
capPARAMS->Parameters.SetFile.ReplaceIfExists
|
|
));
|
|
|
|
RxLog(("SetFileInfo %lx %lx %lx\n",RxContext,capFcb,capFobx));
|
|
RxWmiLog(LOG,
|
|
RxCommonSetInformation_1,
|
|
LOGPTR(RxContext)
|
|
LOGPTR(capFcb)
|
|
LOGPTR(capFobx));
|
|
RxLog((" alsosfi %lx %lx %ld %lx\n",
|
|
capReqPacket->AssociatedIrp.SystemBuffer,
|
|
capPARAMS->Parameters.QueryFile.Length,
|
|
capPARAMS->Parameters.QueryFile.FileInformationClass,
|
|
capPARAMS->Parameters.SetFile.ReplaceIfExists
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxCommonSetInformation_2,
|
|
LOGPTR(capReqPacket->AssociatedIrp.SystemBuffer)
|
|
LOGULONG(capPARAMS->Parameters.QueryFile.Length)
|
|
LOGULONG(capPARAMS->Parameters.QueryFile.FileInformationClass)
|
|
LOGUCHAR(capPARAMS->Parameters.SetFile.ReplaceIfExists));
|
|
|
|
FcbAcquired = FALSE;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
try {
|
|
// Case on the type of open we're dealing with
|
|
switch (TypeOfOpen) {
|
|
case RDBSS_NTC_STORAGE_TYPE_FILE:
|
|
|
|
if (!FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
|
|
//
|
|
// We check whether we can proceed
|
|
// based on the state of the file oplocks.
|
|
//
|
|
|
|
Status = FsRtlCheckOplock( &capFcb->Specific.Fcb.Oplock,
|
|
capReqPacket,
|
|
RxContext,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
try_return( Status );
|
|
}
|
|
|
|
//
|
|
// Set the flag indicating if Fast I/O is possible this for LOCAL filesystems
|
|
//
|
|
|
|
//capFcb->Header.IsFastIoPossible = RxIsFastIoPossible( capFcb );
|
|
}
|
|
break;
|
|
|
|
case RDBSS_NTC_STORAGE_TYPE_DIRECTORY:
|
|
case RDBSS_NTC_STORAGE_TYPE_UNKNOWN:
|
|
case RDBSS_NTC_SPOOLFILE:
|
|
break;
|
|
|
|
case RDBSS_NTC_MAILSLOT:
|
|
try_return((Status = STATUS_NOT_IMPLEMENTED));
|
|
break;
|
|
|
|
default:
|
|
DbgPrint ("SetFile, Illegal TypeOfOpen = %08lx\n", TypeOfOpen);
|
|
try_return((Status = STATUS_INVALID_PARAMETER));
|
|
//RxBugCheck( TypeOfOpen, 0, 0 );
|
|
}
|
|
|
|
//
|
|
// If the FileInformationClass is FileEndOfFileInformation and the
|
|
// AdvanceOnly field in IrpSp->Parameters is TRUE then we don't need
|
|
// to proceed any further. Only local file systems care about this
|
|
// call. This is the AdvanceOnly callback – all FAT does with this is
|
|
// use it as a hint of a good time to punch out the directory entry.
|
|
// NTFS is much the same way. This is pure PagingIo (dovetailing with
|
|
// lazy writer sync) to metadata streams and can’t block behind other
|
|
// user file cached IO.
|
|
//
|
|
if (FileInformationClass == FileEndOfFileInformation) {
|
|
if (capPARAMS->Parameters.SetFile.AdvanceOnly) {
|
|
RxDbgTrace(-1, Dbg, ("RxCommonSetInfo (no advance) -> %08lx\n", RxContext));
|
|
RxLog(("RxCommonSetInfo SetEofAdvance-NOT! %lx\n", RxContext));
|
|
RxWmiLog(LOG,
|
|
RxSetEndOfFileInfo_2,
|
|
LOGPTR(RxContext));
|
|
try_return(Status = STATUS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
//
|
|
// In the following two cases, we cannot have creates occuring
|
|
// while we are here, so acquire the exclusive lock on netroot prefix table.
|
|
//
|
|
|
|
if ((FileInformationClass == FileDispositionInformation) ||
|
|
(FileInformationClass == FileRenameInformation)) {
|
|
RxPurgeRelatedFobxs(
|
|
(PNET_ROOT)capFcb->pNetRoot,
|
|
RxContext,
|
|
ATTEMPT_FINALIZE_ON_PURGE,
|
|
capFcb);
|
|
|
|
RxScavengeFobxsForNetRoot(
|
|
(PNET_ROOT)capFcb->pNetRoot,
|
|
capFcb);
|
|
|
|
if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, Wait)) {
|
|
|
|
RxDbgTrace(0, Dbg, ("Cannot acquire NetRootTableLock\n", 0));
|
|
|
|
Status = STATUS_PENDING;
|
|
RxContext->PostRequest = TRUE;
|
|
|
|
try_return( Status );
|
|
}
|
|
|
|
NetRootTableLockAcquired = TRUE;
|
|
}
|
|
|
|
//
|
|
// Acquire exclusive access to the Fcb, We use exclusive
|
|
// because it is probable that the subroutines
|
|
// that we call will need to monkey with file allocation,
|
|
// create/delete extra fcbs. So we're willing to pay the
|
|
// cost of exclusive Fcb access.
|
|
//
|
|
// Note that we do not acquire the resource for paging file
|
|
// operations in order to avoid deadlock with Mm.
|
|
//
|
|
|
|
if (!FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
|
|
Status = RxAcquireExclusiveFcb( RxContext, capFcb );
|
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|
|
|
RxDbgTrace(0, Dbg, ("Cannot acquire Fcb\n", 0));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
RxContext->PostRequest = TRUE;
|
|
|
|
try_return( Status );
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
try_return( Status );
|
|
}
|
|
|
|
FcbAcquired = TRUE;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Based on the information class we'll do different
|
|
// actions. Each of the procedures that we're calling will either
|
|
// complete the request of send the request off to the fsp
|
|
// to do the work.
|
|
//
|
|
|
|
switch (FileInformationClass) {
|
|
|
|
case FileBasicInformation:
|
|
|
|
Status = RxSetBasicInfo( RxContext );
|
|
break;
|
|
|
|
case FileDispositionInformation:
|
|
{
|
|
PFILE_DISPOSITION_INFORMATION Buffer;
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
// Check if the user wants to delete the file; if so,
|
|
// check for situations where we cannot delete.
|
|
|
|
if (Buffer->DeleteFile) {
|
|
// Make sure there is no process mapping this file as an image.
|
|
|
|
if (!MmFlushImageSection(
|
|
&capFcb->NonPaged->SectionObjectPointers,
|
|
MmFlushForDelete)) {
|
|
|
|
RxDbgTrace(-1, Dbg, ("Cannot delete user mapped image\n", 0));
|
|
|
|
Status = STATUS_CANNOT_DELETE;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
// In the case of disposition information this name is being
|
|
// deleted. In such cases the collapsing of new create requests
|
|
// onto this FCB should be prohibited. This can be accomplished
|
|
// by removing the FCB name from the FCB table. Subsequently the
|
|
// FCB table lock can be dropped.
|
|
|
|
ASSERT(FcbAcquired && NetRootTableLockAcquired);
|
|
|
|
RxRemoveNameNetFcb(capFcb);
|
|
|
|
RxReleaseFcbTableLock(&NetRoot->FcbTable);
|
|
NetRootTableLockAcquired = FALSE;
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = RxSetDispositionInfo( RxContext );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FileMoveClusterInformation:
|
|
case FileLinkInformation:
|
|
case FileRenameInformation:
|
|
|
|
//
|
|
// We proceed with this operation only if we can wait
|
|
//
|
|
|
|
if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT)) {
|
|
|
|
Status = RxFsdPostRequest( RxContext );
|
|
|
|
} else {
|
|
ClearFlag(capFcb->FcbState,FCB_STATE_COLLAPSING_ENABLED);
|
|
|
|
Status = RxSetRenameInfo( RxContext );
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(FileInformationClass == FileRenameInformation)) {
|
|
ASSERT(FcbAcquired && NetRootTableLockAcquired);
|
|
|
|
RxRemoveNameNetFcb(capFcb);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
Status = RxSetPositionInfo( RxContext );
|
|
break;
|
|
|
|
|
|
case FileAllocationInformation:
|
|
|
|
Status = RxSetAllocationInfo( RxContext );
|
|
break;
|
|
|
|
case FileEndOfFileInformation:
|
|
|
|
Status = RxSetEndOfFileInfo( RxContext );
|
|
break;
|
|
|
|
case FilePipeInformation:
|
|
case FilePipeLocalInformation:
|
|
case FilePipeRemoteInformation:
|
|
|
|
Status = RxSetPipeInfo(RxContext);
|
|
break;
|
|
|
|
case FileValidDataLengthInformation:
|
|
|
|
if(!MmCanFileBeTruncated(&capFcb->NonPaged->SectionObjectPointers, NULL)) {
|
|
Status = STATUS_USER_MAPPED_FILE;
|
|
break;
|
|
}
|
|
Status = RxSetSimpleInfo(RxContext);
|
|
break;
|
|
|
|
case FileShortNameInformation:
|
|
|
|
Status = RxSetSimpleInfo(RxContext);
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
try_exit:
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
RxContext->PostRequest) {
|
|
Status = RxFsdPostRequest( RxContext );
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugUnwind( RxCommonSetInformation );
|
|
|
|
if (FcbAcquired)
|
|
{
|
|
RxReleaseFcb( RxContext, capFcb );
|
|
}
|
|
|
|
if (NetRootTableLockAcquired)
|
|
{
|
|
RxReleaseFcbTableLock(&NetRoot->FcbTable);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxCommonSetInformation -> %08lx\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetBasicInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Interal Support Routine)
|
|
This routine performs the set basic information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
RxContext - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject;
|
|
|
|
|
|
PFILE_BASIC_INFORMATION Buffer;
|
|
|
|
BOOLEAN ModifyCreation = FALSE;
|
|
BOOLEAN ModifyLastAccess = FALSE;
|
|
BOOLEAN ModifyLastWrite = FALSE;
|
|
BOOLEAN ModifyLastChange = FALSE;
|
|
ULONG NotifyFilter = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetBasicInfo...\n", 0));
|
|
RxLog(("RxSetBasicInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxSetBasicInfo,
|
|
LOGPTR(RxContext));
|
|
//
|
|
// call down. if we're successful, then fixup all the fcb data.
|
|
|
|
Status = RxpSetInfoMiniRdr(RxContext,FileBasicInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(-1, Dbg, ("RxSetBasicInfo -> %08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// now we have to update the info in the fcb, both the absolute info AND whether changes were made
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
try {
|
|
|
|
//
|
|
// Check if the user specified a non-zero creation time
|
|
//
|
|
|
|
if (Buffer->CreationTime.QuadPart != 0 ) {
|
|
|
|
ModifyCreation = TRUE;
|
|
|
|
NotifyFilter = FILE_NOTIFY_CHANGE_CREATION;
|
|
}
|
|
|
|
//
|
|
// Check if the user specified a non-zero last access time
|
|
//
|
|
|
|
if (Buffer->LastAccessTime.QuadPart != 0 ) {
|
|
|
|
ModifyLastAccess = TRUE;
|
|
|
|
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
|
|
}
|
|
|
|
//
|
|
// Check if the user specified a non-zero last write time
|
|
//
|
|
|
|
if (Buffer->LastWriteTime.QuadPart != 0 ) {
|
|
|
|
|
|
ModifyLastWrite = TRUE;
|
|
|
|
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
|
|
}
|
|
|
|
|
|
if (Buffer->ChangeTime.QuadPart != 0 ) {
|
|
|
|
|
|
ModifyLastChange = TRUE;
|
|
|
|
//NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_CHANGE;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if the user specified a non zero file attributes byte
|
|
//
|
|
|
|
if (Buffer->FileAttributes != 0) {
|
|
|
|
USHORT Attributes;
|
|
|
|
//
|
|
// Remove the normal attribute flag
|
|
//
|
|
|
|
Attributes = (USHORT)(Buffer->FileAttributes & ~FILE_ATTRIBUTE_NORMAL);
|
|
|
|
//
|
|
// Make sure that for a file the directory bit is not set
|
|
// and for a directory that the bit is set
|
|
//
|
|
|
|
if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) {
|
|
|
|
Attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
} else {
|
|
|
|
Attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
|
}
|
|
|
|
//
|
|
// Mark the FcbState temporary flag correctly.
|
|
//
|
|
|
|
if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY)) {
|
|
|
|
SetFlag( capFcb->FcbState, FCB_STATE_TEMPORARY );
|
|
|
|
SetFlag( capFileObject->Flags, FO_TEMPORARY_FILE );
|
|
|
|
} else {
|
|
|
|
ClearFlag( capFcb->FcbState, FCB_STATE_TEMPORARY );
|
|
|
|
ClearFlag( capFileObject->Flags, FO_TEMPORARY_FILE );
|
|
}
|
|
|
|
//
|
|
// Set the new attributes byte, and mark the bcb dirty
|
|
//
|
|
|
|
capFcb->Attributes = Attributes;
|
|
|
|
NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
|
|
}
|
|
|
|
if ( ModifyCreation ) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
capFcb->CreationTime = Buffer->CreationTime;
|
|
//
|
|
// Now because the user just set the creation time we
|
|
// better not set the creation time on close
|
|
//
|
|
|
|
SetFlag( capFobx->Flags, FOBX_FLAG_USER_SET_CREATION );
|
|
}
|
|
|
|
if ( ModifyLastAccess ) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
capFcb->LastAccessTime = Buffer->LastAccessTime;
|
|
//
|
|
// Now because the user just set the last access time we
|
|
// better not set the last access time on close
|
|
//
|
|
|
|
SetFlag( capFobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS );
|
|
}
|
|
|
|
if ( ModifyLastWrite ) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
capFcb->LastWriteTime = Buffer->LastWriteTime;
|
|
//
|
|
// Now because the user just set the last write time we
|
|
// better not set the last write time on close
|
|
//
|
|
|
|
SetFlag( capFobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE );
|
|
}
|
|
|
|
if ( ModifyLastChange ) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
capFcb->LastChangeTime = Buffer->ChangeTime;
|
|
//
|
|
// Now because the user just set the last write time we
|
|
// better not set the last write time on close
|
|
//
|
|
|
|
SetFlag( capFobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE );
|
|
}
|
|
|
|
//
|
|
// If we modified any of the values, we report this to the notify
|
|
// package.
|
|
//
|
|
|
|
if (NotifyFilter != 0) {
|
|
|
|
RxNotifyReportChange( RxContext,
|
|
capFcb->Vcb,
|
|
capFcb,
|
|
NotifyFilter,
|
|
FILE_ACTION_MODIFIED );
|
|
}
|
|
|
|
//try_exit: NOTHING;
|
|
} finally {
|
|
|
|
DebugUnwind( RxSetBasicInfo );
|
|
|
|
//RxUnpinBcb( RxContext, DirentBcb );
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetBasicInfo -> %08lx\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetDispositionInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the set disposition information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
RxContext - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
PFILE_DISPOSITION_INFORMATION Buffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetDispositionInfo...\n", 0));
|
|
RxLog(("RxSetDispositionInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxSetDispositionInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
//call down and check for success
|
|
|
|
Status = RxpSetInfoMiniRdr(RxContext,FileDispositionInformation);;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(-1, Dbg, ("RxSetDispositionInfo -> %08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// if successful, record the correct state in the fcb
|
|
|
|
if (Buffer->DeleteFile) {
|
|
|
|
capFcb->FcbState |= FCB_STATE_DELETE_ON_CLOSE;
|
|
capFileObject->DeletePending = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The user doesn't want to delete the file so clear
|
|
// the delete on close bit
|
|
//
|
|
|
|
RxDbgTrace(0, Dbg, ("User want to not delete file\n", 0));
|
|
|
|
capFcb->FcbState &= ~FCB_STATE_DELETE_ON_CLOSE;
|
|
capFileObject->DeletePending = FALSE;
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetDispositionInfo -> RxStatus(SUCCESS)\n", 0));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetRenameInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the set name information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetRenameInfo ......FileObj = %08lx\n",
|
|
capPARAMS->Parameters.SetFile.FileObject));
|
|
RxLog(("RxSetRenameInfo %lx %lx\n",
|
|
capPARAMS->Parameters.SetFile.FileObject,
|
|
capPARAMS->Parameters.SetFile.ReplaceIfExists ));
|
|
RxWmiLog(LOG,
|
|
RxSetRenameInfo,
|
|
LOGPTR(capPARAMS->Parameters.SetFile.FileObject)
|
|
LOGUCHAR(capPARAMS->Parameters.SetFile.ReplaceIfExists));
|
|
|
|
RxContext->Info.ReplaceIfExists = capPARAMS->Parameters.SetFile.ReplaceIfExists;
|
|
if (capPARAMS->Parameters.SetFile.FileObject){
|
|
// here we have to translate the name. the fcb of the fileobject has the
|
|
// translation already....all we have to do is to allocate a buffer, copy
|
|
// and calldown
|
|
PFILE_OBJECT RenameFileObject = capPARAMS->Parameters.SetFile.FileObject;
|
|
PFCB RenameFcb = (PFCB)(RenameFileObject->FsContext);
|
|
PFILE_RENAME_INFORMATION RenameInformation;
|
|
ULONG allocate_size;
|
|
|
|
ASSERT (NodeType(RenameFcb)==RDBSS_NTC_OPENTARGETDIR_FCB);
|
|
|
|
RxDbgTrace(0, Dbg, ("-->RenameTarget is %wZ,over=%08lx\n",
|
|
&(RenameFcb->FcbTableEntry.Path),
|
|
capFcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize));
|
|
if (RenameFcb->pNetRoot != capFcb->pNetRoot) {
|
|
RxDbgTrace(-1, Dbg, ("RxSetRenameInfo -> %s\n", "NOT SAME DEVICE!!!!!!"));
|
|
return(STATUS_NOT_SAME_DEVICE);
|
|
}
|
|
|
|
allocate_size = FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName[0])
|
|
+ RenameFcb->FcbTableEntry.Path.Length
|
|
+ capFcb->pNetRoot->DiskParameters.RenameInfoOverallocationSize;
|
|
RxDbgTrace(0, Dbg, ("-->AllocSize is %08lx\n", allocate_size));
|
|
RenameInformation = RxAllocatePool( PagedPool, allocate_size );
|
|
if (RenameInformation != NULL) {
|
|
try {
|
|
*RenameInformation = *((PFILE_RENAME_INFORMATION)(capReqPacket->AssociatedIrp.SystemBuffer));
|
|
RenameInformation->FileNameLength = RenameFcb->FcbTableEntry.Path.Length;
|
|
|
|
RtlMoveMemory(
|
|
&RenameInformation->FileName[0],
|
|
RenameFcb->FcbTableEntry.Path.Buffer,
|
|
RenameFcb->FcbTableEntry.Path.Length);
|
|
|
|
RxContext->Info.FileInformationClass = (capPARAMS->Parameters.SetFile.FileInformationClass);
|
|
RxContext->Info.Buffer = RenameInformation;
|
|
RxContext->Info.Length = allocate_size;
|
|
MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfo,(RxContext));
|
|
|
|
//we don't change the name in the fcb? a la rdr1
|
|
} finally {
|
|
RxFreePool(RenameInformation);
|
|
}
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
Status = RxpSetInfoMiniRdr(
|
|
RxContext,
|
|
capPARAMS->Parameters.SetFile.FileInformationClass);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetRenameInfo -> %08lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetPositionInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the set position information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
RxContext - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
//RXSTATUS Status;
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject;
|
|
|
|
PFILE_POSITION_INFORMATION Buffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetPositionInfo...\n", 0));
|
|
RxLog(("RxSetPositionInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxSetPositionInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
//this does not call down.........
|
|
////MINIRDR_CALL(Status,Fcb->NetRoot,MRxSetPositionInfo,(RxContext));
|
|
//SETINFO_MINIRDR_CALL(FilePositionInformation);;
|
|
//
|
|
//if (!NT_SUCCESS(Status)) {
|
|
// RxDbgTrace(-1, Dbg, ("RxSetBasicInfo -> %08lx\n", Status));
|
|
// return Status;
|
|
//}
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Check if the file does not use intermediate buffering. If it
|
|
// does not use intermediate buffering then the new position we're
|
|
// supplied must be aligned properly for the device
|
|
//
|
|
|
|
if (FlagOn( capFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
DeviceObject = capPARAMS->DeviceObject;
|
|
|
|
if ((Buffer->CurrentByteOffset.LowPart & DeviceObject->AlignmentRequirement) != 0) {
|
|
|
|
RxDbgTrace(0, Dbg, ("Cannot set position due to aligment conflict\n", 0));
|
|
RxDbgTrace(-1, Dbg, ("RxSetPositionInfo -> %08lx\n", STATUS_INVALID_PARAMETER));
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The input parameter is fine so set the current byte offset and
|
|
// complete the request
|
|
//
|
|
|
|
RxDbgTrace(0, Dbg, ("Set the new position to %08lx\n", Buffer->CurrentByteOffset));
|
|
|
|
capFileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetPositionInfo -> %08lx\n", STATUS_SUCCESS));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetAllocationInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the set Allocation information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
RxContext - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
PFILE_ALLOCATION_INFORMATION Buffer;
|
|
|
|
LONGLONG NewAllocationSize;
|
|
|
|
BOOLEAN CacheMapInitialized = FALSE;
|
|
LARGE_INTEGER OriginalFileSize;
|
|
LARGE_INTEGER OriginalAllocationSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
NewAllocationSize = Buffer->AllocationSize.QuadPart;
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetAllocationInfo.. to %08lx\n", NewAllocationSize));
|
|
RxLog(("SetAlloc %lx %lx %lx\n", capFcb->Header.FileSize.LowPart,
|
|
(ULONG)NewAllocationSize, capFcb->Header.AllocationSize.LowPart
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxSetAllocationInfo_1,
|
|
LOGULONG(capFcb->Header.FileSize.LowPart)
|
|
LOGULONG((ULONG)NewAllocationSize)
|
|
LOGULONG(capFcb->Header.AllocationSize.LowPart));
|
|
|
|
// This is kinda gross, but if the file is not cached, but there is
|
|
// a data section, we have to cache the file to avoid a bunch of
|
|
// extra work.
|
|
|
|
if ((capFileObject->SectionObjectPointer->DataSectionObject != NULL) &&
|
|
(capFileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
|
|
(capReqPacket->RequestorMode != KernelMode)) {
|
|
|
|
if ( FlagOn( capFileObject->Flags, FO_CLEANUP_COMPLETE ) ) {
|
|
return STATUS_FILE_CLOSED;
|
|
}
|
|
|
|
RxAdjustAllocationSizeforCC(capFcb);
|
|
|
|
//
|
|
// Now initialize the cache map.
|
|
//
|
|
|
|
CcInitializeCacheMap( capFileObject,
|
|
(PCC_FILE_SIZES)&capFcb->Header.AllocationSize,
|
|
FALSE,
|
|
&RxData.CacheManagerCallbacks,
|
|
capFcb );
|
|
|
|
CacheMapInitialized = TRUE;
|
|
}
|
|
|
|
//LOCAL.FSD this is a local fsd thing
|
|
////
|
|
//// Now mark the fact that the file needs to be truncated on close
|
|
////
|
|
//
|
|
//capFcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
|
|
|
|
//
|
|
// Now mark that the time on the dirent needs to be updated on close.
|
|
//
|
|
|
|
SetFlag( capFileObject->Flags, FO_FILE_MODIFIED );
|
|
|
|
try {
|
|
// Check here if we will be decreasing file size and synchonize with
|
|
// paging IO.
|
|
|
|
RxGetFileSizeWithLock(capFcb,&OriginalFileSize.QuadPart);
|
|
|
|
if ( OriginalFileSize.QuadPart > Buffer->AllocationSize.QuadPart ) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( capFileObject->SectionObjectPointer,
|
|
&Buffer->AllocationSize )) {
|
|
|
|
try_return( Status = STATUS_USER_MAPPED_FILE );
|
|
}
|
|
|
|
|
|
(VOID)RxAcquirePagingIoResource(capFcb,RxContext);
|
|
|
|
RxSetFileSizeWithLock(capFcb,&NewAllocationSize);
|
|
|
|
//
|
|
// If we reduced the file size to less than the ValidDataLength,
|
|
// adjust the VDL.
|
|
//
|
|
|
|
if (capFcb->Header.ValidDataLength.QuadPart > NewAllocationSize) {
|
|
|
|
capFcb->Header.ValidDataLength.QuadPart = NewAllocationSize;
|
|
}
|
|
|
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|
}
|
|
|
|
OriginalAllocationSize.QuadPart = capFcb->Header.AllocationSize.QuadPart;
|
|
capFcb->Header.AllocationSize.QuadPart = NewAllocationSize;
|
|
|
|
Status = RxpSetInfoMiniRdr(
|
|
RxContext,
|
|
FileAllocationInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
capFcb->Header.AllocationSize.QuadPart = OriginalAllocationSize.QuadPart;
|
|
RxDbgTrace(-1, Dbg, ("RxSetAllocationInfo -> %08lx\n", Status));
|
|
try_return (Status);
|
|
}
|
|
|
|
//
|
|
// Now check if we needed to change the file size accordingly.
|
|
//
|
|
|
|
if( OriginalAllocationSize.QuadPart != NewAllocationSize ) {
|
|
|
|
//
|
|
// Tell the cache manager we reduced the file size or increased the allocationsize
|
|
// The call is unconditional, because MM always wants to know.
|
|
//
|
|
|
|
try {
|
|
|
|
CcSetFileSizes( capFileObject, (PCC_FILE_SIZES)&capFcb->Header.AllocationSize );
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
Status = GetExceptionCode();
|
|
|
|
//
|
|
// Cache manager was not able to extend the file. Restore the file to
|
|
// its previous state.
|
|
//
|
|
// NOTE: If this call to the mini-RDR fails, there is nothing we can do.
|
|
//
|
|
|
|
capFcb->Header.AllocationSize.QuadPart = OriginalAllocationSize.QuadPart;
|
|
|
|
RxpSetInfoMiniRdr( RxContext,
|
|
FileAllocationInformation );
|
|
|
|
try_return( Status );
|
|
}
|
|
|
|
//ASSERT( capFileObject->DeleteAccess || capFileObject->WriteAccess );
|
|
|
|
//
|
|
// Report that we just reduced the file size.
|
|
//
|
|
|
|
RxNotifyReportChange(
|
|
RxContext,
|
|
capFcb->Vcb,
|
|
capFcb,
|
|
FILE_NOTIFY_CHANGE_SIZE,
|
|
FILE_ACTION_MODIFIED );
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
} finally {
|
|
if (CacheMapInitialized) {
|
|
|
|
CcUninitializeCacheMap( capFileObject, NULL, NULL );
|
|
}
|
|
}
|
|
|
|
RxLog(("SetAllocExit %lx %lx\n",
|
|
capFcb->Header.FileSize.LowPart,
|
|
capFcb->Header.AllocationSize.LowPart
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxSetAllocationInfo_2,
|
|
LOGULONG(capFcb->Header.FileSize.LowPart)
|
|
LOGULONG(capFcb->Header.AllocationSize.LowPart));
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetAllocationInfo -> %08lx\n", STATUS_SUCCESS));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetEndOfFileInfo (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the set End of File information for rx. It either
|
|
completes the request or enqueues it off to the fsp.
|
|
|
|
Arguments:
|
|
|
|
RxContext - Supplies the irp being processed
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
NTSTATUS SetFileSizeStatus;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject;
|
|
|
|
PFILE_END_OF_FILE_INFORMATION Buffer;
|
|
|
|
LONGLONG NewFileSize;
|
|
LONGLONG OriginalFileSize;
|
|
LONGLONG OriginalAllocationSize;
|
|
LONGLONG OriginalValidDataLength;
|
|
|
|
BOOLEAN CacheMapInitialized = FALSE;
|
|
BOOLEAN PagingIoResourceAcquired = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
Buffer = capReqPacket->AssociatedIrp.SystemBuffer;
|
|
NewFileSize = Buffer->EndOfFile.QuadPart;
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetEndOfFileInfo...Old,New,Alloc %08lx,%08lx,%08lx\n",
|
|
capFcb->Header.FileSize.LowPart,
|
|
(ULONG)NewFileSize,
|
|
capFcb->Header.AllocationSize.LowPart));
|
|
RxLog(("SetEof %lx %lx %lx %lx\n", RxContext, capFcb->Header.FileSize.LowPart,
|
|
(ULONG)NewFileSize, capFcb->Header.AllocationSize.LowPart
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxSetEndOfFileInfo_1,
|
|
LOGPTR(RxContext)
|
|
LOGULONG(capFcb->Header.FileSize.LowPart)
|
|
LOGULONG((ULONG)NewFileSize)
|
|
LOGULONG(capFcb->Header.AllocationSize.LowPart));
|
|
|
|
//
|
|
// File Size changes are only allowed on a file and not a directory
|
|
//
|
|
|
|
if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_FILE) {
|
|
|
|
RxDbgTrace(0, Dbg, ("Cannot change size of a directory\n", 0));
|
|
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
try {
|
|
// remember everything
|
|
OriginalFileSize = capFcb->Header.FileSize.QuadPart;
|
|
OriginalAllocationSize = capFcb->Header.AllocationSize.QuadPart;
|
|
OriginalValidDataLength = capFcb->Header.ValidDataLength.QuadPart;
|
|
|
|
//
|
|
// This is kinda gross, but if the file is not cached, but there is
|
|
// a data section, we have to cache the file to avoid a bunch of
|
|
// extra work.
|
|
//
|
|
|
|
if ((capFileObject->SectionObjectPointer->DataSectionObject != NULL) &&
|
|
(capFileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
|
|
(capReqPacket->RequestorMode != KernelMode)) {
|
|
|
|
if ( FlagOn( capFileObject->Flags, FO_CLEANUP_COMPLETE ) ) {
|
|
try_return( STATUS_FILE_CLOSED );
|
|
}
|
|
|
|
RxAdjustAllocationSizeforCC(capFcb);
|
|
|
|
//
|
|
// Now initialize the cache map.
|
|
//
|
|
|
|
CcInitializeCacheMap( capFileObject,
|
|
(PCC_FILE_SIZES)&capFcb->Header.AllocationSize,
|
|
FALSE,
|
|
&RxData.CacheManagerCallbacks,
|
|
capFcb );
|
|
|
|
CacheMapInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Do a special case here for the lazy write of file sizes.
|
|
//
|
|
|
|
// only a localFSD does this....not a rdr. this is consistent with the rdr1 imnplementaion
|
|
if (FALSE &&capPARAMS->Parameters.SetFile.AdvanceOnly) {
|
|
|
|
ASSERT(!"you shouldn't be trying a advance only.....");
|
|
//
|
|
// Only attempt this if the file hasn't been "deleted on close"
|
|
//
|
|
|
|
if (FALSE && !capFileObject->DeletePending) {
|
|
|
|
//
|
|
// Make sure we don't set anything higher than the alloc size. current
|
|
// filesize is the best. the cachemanager will try to extend to a page
|
|
// boundary if you're not careful!!!
|
|
//
|
|
|
|
if ( NewFileSize > capFcb->Header.FileSize.QuadPart ){ //capture the header ptr
|
|
|
|
NewFileSize = capFcb->Header.FileSize.QuadPart;
|
|
//try_return (Status = RxStatus(SUCCESS));
|
|
|
|
}
|
|
|
|
ASSERT( NewFileSize <= capFcb->Header.AllocationSize.QuadPart );
|
|
|
|
Status = RxpSetInfoMiniRdr(
|
|
RxContext,
|
|
FileEndOfFileInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(-1, Dbg, ("RxSetEndOfFileInfo1 status -> %08lx\n", Status));
|
|
try_return (Status);
|
|
}
|
|
|
|
RxNotifyReportChange(
|
|
RxContext,
|
|
Vcb,
|
|
capFcb,
|
|
FILE_NOTIFY_CHANGE_SIZE,
|
|
FILE_ACTION_MODIFIED );
|
|
} else {
|
|
|
|
RxDbgTrace(0, Dbg, ("Cannot set size on deleted file.\n", 0));
|
|
}
|
|
|
|
try_return( Status = STATUS_SUCCESS );
|
|
}
|
|
|
|
//
|
|
// At this point we have enough allocation for the file.
|
|
// So check if we are really changing the file size
|
|
//
|
|
|
|
if (capFcb->Header.FileSize.QuadPart != NewFileSize) {
|
|
|
|
if ( NewFileSize < capFcb->Header.FileSize.QuadPart ) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( capFileObject->SectionObjectPointer,
|
|
&Buffer->EndOfFile )) {
|
|
|
|
try_return( Status = STATUS_USER_MAPPED_FILE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// MM always wants to know if the filesize is changing;
|
|
// serialize here with paging io since we are truncating the file size.
|
|
//
|
|
|
|
PagingIoResourceAcquired =
|
|
RxAcquirePagingIoResource(capFcb,RxContext);
|
|
|
|
//
|
|
// Set the new file size
|
|
//
|
|
|
|
capFcb->Header.FileSize.QuadPart = NewFileSize;
|
|
|
|
//
|
|
// If we reduced the file size to less than the ValidDataLength,
|
|
// adjust the VDL.
|
|
//
|
|
|
|
if (capFcb->Header.ValidDataLength.QuadPart > NewFileSize) {
|
|
|
|
capFcb->Header.ValidDataLength.QuadPart = NewFileSize;
|
|
}
|
|
|
|
//
|
|
// Check if the new file size is greater than the current
|
|
// allocation size. If it is then we need to increase the
|
|
// allocation size. A clever minirdr might override this calculation
|
|
// with a bigger number.
|
|
//
|
|
|
|
//if ( NewFileSize > capFcb->Header.AllocationSize.QuadPart ) {
|
|
|
|
//
|
|
// Change the file allocation
|
|
//
|
|
|
|
capFcb->Header.AllocationSize.QuadPart = NewFileSize;
|
|
//}
|
|
|
|
Status = RxpSetInfoMiniRdr(
|
|
RxContext,
|
|
FileEndOfFileInformation);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
if (PagingIoResourceAcquired) {
|
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|
PagingIoResourceAcquired = FALSE;
|
|
}
|
|
|
|
//
|
|
// We must now update the cache mapping (benign if not cached).
|
|
//
|
|
|
|
SetFileSizeStatus = STATUS_SUCCESS;
|
|
|
|
try {
|
|
CcSetFileSizes(
|
|
capFileObject,
|
|
(PCC_FILE_SIZES)&capFcb->Header.AllocationSize );
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
SetFileSizeStatus = GetExceptionCode();
|
|
}
|
|
|
|
if (SetFileSizeStatus != STATUS_SUCCESS) {
|
|
Status = SetFileSizeStatus;
|
|
try_return(Status);
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
//
|
|
// Report that we just changed the file size.
|
|
//
|
|
|
|
RxNotifyReportChange(
|
|
RxContext,
|
|
Vcb,
|
|
capFcb,
|
|
FILE_NOTIFY_CHANGE_SIZE,
|
|
FILE_ACTION_MODIFIED );
|
|
}
|
|
|
|
//LOCAL.FSD this is a local fsd idea
|
|
////
|
|
//// Mark the fact that the file will need to checked for
|
|
//// truncation on cleanup.
|
|
////
|
|
//
|
|
//SetFlag( capFcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE );
|
|
} else {
|
|
//
|
|
// Set our return status to success
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set this handle as having modified the file
|
|
//
|
|
|
|
capFileObject->Flags |= FO_FILE_MODIFIED;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
DebugUnwind( RxSetEndOfFileInfo );
|
|
|
|
if (( AbnormalTermination() || !NT_SUCCESS(Status) )) {
|
|
RxDbgTrace(-1, Dbg, ("RxSetEndOfFileInfo2 status -> %08lx\n", Status));
|
|
|
|
capFcb->Header.FileSize.QuadPart = OriginalFileSize;
|
|
capFcb->Header.AllocationSize.QuadPart = OriginalAllocationSize;
|
|
capFcb->Header.ValidDataLength.QuadPart = OriginalValidDataLength;
|
|
|
|
if (capFileObject->SectionObjectPointer->SharedCacheMap != NULL) {
|
|
*CcGetFileSizePointer(capFileObject) = capFcb->Header.FileSize;
|
|
}
|
|
|
|
RxLog(("SetEofabnormalorbadstatus %lx %lx", RxContext,Status));
|
|
RxWmiLog(LOG,
|
|
RxSetEndOfFileInfo_3,
|
|
LOGPTR(RxContext)
|
|
LOGULONG(Status));
|
|
}
|
|
|
|
if (PagingIoResourceAcquired) {
|
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|
}
|
|
|
|
if (CacheMapInitialized) {
|
|
CcUninitializeCacheMap( capFileObject, NULL, NULL );
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetEndOfFileInfo -> %08lx\n", Status));
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
RxLog(
|
|
("SetEofexit %lx %lx %lx\n",
|
|
capFcb->Header.FileSize.LowPart,
|
|
(ULONG)NewFileSize,
|
|
capFcb->Header.AllocationSize.LowPart
|
|
));
|
|
RxWmiLog(LOG,
|
|
RxSetEndOfFileInfo_4,
|
|
LOGPTR(RxContext)
|
|
LOGULONG(capFcb->Header.FileSize.LowPart)
|
|
LOGULONG((ULONG)NewFileSize)
|
|
LOGULONG(capFcb->Header.AllocationSize.LowPart));
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
#define QUERY_MINIRDR_CALL(FILEINFOCLASS) {\
|
|
MINIRDR_CALL(RxContext->StoredStatus,RxContext,Fcb->MRxDispatch,MRxQueryFileInfo, \
|
|
(RxContext,FILEINFOCLASS,Buffer,pLengthRemaining)); \
|
|
RxDbgTraceUnIndent(-1,Dbg); \
|
|
return RxContext->StoredStatus; }
|
|
|
|
BOOLEAN RxForceQFIPassThrough = FALSE;
|
|
|
|
NTSTATUS
|
|
RxQueryBasicInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the query basic information function for fat.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the call was successful, otherwise the appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryBasicInfo...\n", 0));
|
|
RxLog(("RxQueryBasicInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryBasicInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
// Zero out the output buffer, and set it to indicate that
|
|
// the query is a normal file. Later we might overwrite the
|
|
// attribute.
|
|
RtlZeroMemory( Buffer, sizeof(FILE_BASIC_INFORMATION) );
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileBasicInformation,
|
|
Buffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryStandardInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query standard information function for fat.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
PMRX_SRV_OPEN pSrvOpen;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryStandardInfo...\n", 0));
|
|
RxLog(("RxQueryStandardInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryStandardInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
//
|
|
// Zero out the output buffer, and fill in the number of links
|
|
// and the delete pending flag.
|
|
//
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_STANDARD_INFORMATION) );
|
|
|
|
pSrvOpen = capFobx->pSrvOpen;
|
|
|
|
switch (NodeType(capFcb)) {
|
|
case RDBSS_NTC_STORAGE_TYPE_DIRECTORY:
|
|
case RDBSS_NTC_STORAGE_TYPE_FILE:
|
|
|
|
// If the file was not opened with back up intent then the wrapper has
|
|
// all the information that is required. In the cases that this is
|
|
// specified we fill in the information from the mini redirector. This
|
|
// is because backup pograms rely upon fields that are not available
|
|
// in the wrapper and that which cannot be cached easily.
|
|
|
|
if (!FlagOn(pSrvOpen->CreateOptions,FILE_OPEN_FOR_BACKUP_INTENT)) {
|
|
//copy in all the stuff that we know....it may be enough.....
|
|
Buffer->NumberOfLinks = capFcb->NumberOfLinks;
|
|
Buffer->DeletePending = BooleanFlagOn( capFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
|
|
Buffer->Directory = (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
|
|
|
|
if (Buffer->NumberOfLinks == 0) {
|
|
// This swicth is required because of compatibility reasons with
|
|
// the old redirector.
|
|
Buffer->NumberOfLinks = 1;
|
|
}
|
|
|
|
if (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
|
|
Buffer->AllocationSize = capFcb->Header.AllocationSize;
|
|
//Buffer->EndOfFile = capFcb->Header.FileSize;
|
|
RxGetFileSizeWithLock(capFcb,&Buffer->EndOfFile.QuadPart);
|
|
}
|
|
|
|
if ( !RxForceQFIPassThrough
|
|
&& FlagOn(capFcb->FcbState,FCB_STATE_FILESIZECACHEING_ENABLED) ) {
|
|
|
|
//if we don't have to go to the mini, adjust the size and get out.......
|
|
RxContext->Info.LengthRemaining -= sizeof(FILE_STANDARD_INFORMATION);
|
|
break;
|
|
|
|
}
|
|
}
|
|
// falls thru
|
|
|
|
default:
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileStandardInformation,
|
|
Buffer);
|
|
break;
|
|
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("LengthRemaining = %08lx\n", RxContext->Info.LengthRemaining));
|
|
RxDbgTrace(-1, Dbg, ("RxQueryStandardInfo -> VOID\n", 0));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryInternalInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_INTERNAL_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the query internal information function for fat.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryInternalInfo...\n", 0));
|
|
RxLog(("RxQueryInternalInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryInternalInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileInternalInformation,
|
|
Buffer);
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxQueryInternalInfo...Status %lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryEaInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_EA_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query Ea information function for fat.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryEaInfo...\n", 0));
|
|
RxLog(("RxQueryEaInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryEaInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileEaInformation,
|
|
Buffer);
|
|
|
|
if ((capPARAMS->Parameters.QueryFile.FileInformationClass == FileAllInformation) &&
|
|
(Status == STATUS_NOT_IMPLEMENTED)) {
|
|
RxContext->Info.LengthRemaining -= sizeof( FILE_EA_INFORMATION );
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxQueryEaInfo...Status %lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryPositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_POSITION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query position information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryPositionInfo...\n", 0));
|
|
RxLog(("RxQueryPositionInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryPositionInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
Buffer->CurrentByteOffset = capFileObject->CurrentByteOffset;
|
|
|
|
RxContext->Info.LengthRemaining -= sizeof( FILE_POSITION_INFORMATION );
|
|
|
|
RxDbgTrace( 0, Dbg, ("LengthRemaining = %08lx\n", RxContext->Info.LengthRemaining));
|
|
RxDbgTrace(-1, Dbg, ("RxQueryPositionInfo...Status %lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
RxConjureOriginalName (
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
OUT PLONG pActualNameLength,
|
|
PWCHAR OriginalName,
|
|
IN OUT PLONG pLengthRemaining,
|
|
IN RX_NAME_CONJURING_METHODS NameConjuringMethod
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine conjures up the original name of an Fcb. it is used in querynameinfo below and
|
|
also in RxCanonicalizeAndObtainPieces in the create path for relative opens. for relative opens, we return
|
|
a name of the form \;m:\server\share\.....\name which is how it came down from createfile. otherwise, we give
|
|
back the name relative to the vnetroot.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the Fcb whose original name is to be conjured
|
|
|
|
pActualNameLength - the place to store the actual name length. not all of it will be conjured
|
|
if the buffer is too small.
|
|
|
|
OriginalName - Supplies a pointer to the buffer where the name is to conjured
|
|
|
|
pLengthRemaining - Supplies the length of the Name buffer in bytes, and receives the
|
|
remaining bytes free in the buffer upon return.
|
|
|
|
VNetRootAsPrefix - if true, give back the name as "\;m:", if false, give it back w/o net part.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
|
|
--*/
|
|
{
|
|
PNET_ROOT NetRoot = (PNET_ROOT)Fcb->pNetRoot;
|
|
PUNICODE_STRING NetRootName = &NetRoot->PrefixEntry.Prefix;
|
|
PUNICODE_STRING FcbName = &Fcb->FcbTableEntry.Path;
|
|
PWCHAR CopyBuffer,FcbNameBuffer;
|
|
LONG BytesToCopy,BytesToCopy2;
|
|
LONG FcbNameSuffixLength,PreFcbLength;
|
|
LONG InnerPrefixLength;
|
|
|
|
RX_NAME_CONJURING_METHODS OrigianlNameConjuringMethod = NameConjuringMethod;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxConjureOriginalFilename...\n", 0));
|
|
RxDbgTrace(0, Dbg, ("--> NetRootName = %wZ\n", NetRootName));
|
|
RxDbgTrace(0, Dbg, ("--> FcbNameName = %wZ\n", FcbName));
|
|
RxDbgTrace(0, Dbg, ("--> ,AddedBS = %08lx\n",
|
|
FlagOn(Fcb->FcbState,FCB_STATE_ADDEDBACKSLASH)));
|
|
|
|
// here, we have to copy in the vnetrootprefix and the servershare stuff.
|
|
// first figure out the size of the two pieces: prefcblength is the part that comes
|
|
// from the [v]netroot; fcbnamesuffix is the part that is left of the filename after
|
|
// the vnetroot prefix is skipped
|
|
|
|
if ((!Fcb->VNetRoot) ||
|
|
(Fcb->VNetRoot->PrefixEntry.Prefix.Buffer[1] != L';') ||
|
|
(FlagOn(Fobx->Flags,FOBX_FLAG_UNC_NAME)) ){
|
|
|
|
CopyBuffer = NetRootName->Buffer;
|
|
PreFcbLength = NetRootName->Length;
|
|
InnerPrefixLength = 0;
|
|
|
|
NameConjuringMethod = VNetRoot_As_Prefix; //override whatever was passed
|
|
|
|
} else {
|
|
|
|
PV_NET_ROOT VNetRoot = Fcb->VNetRoot;
|
|
PUNICODE_STRING VNetRootName = &VNetRoot->PrefixEntry.Prefix;
|
|
|
|
ASSERT( NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT );
|
|
RxDbgTrace(0, Dbg, ("--> VNetRootName = %wZ\n", VNetRootName));
|
|
RxDbgTrace(0, Dbg, ("--> VNetRootNamePrefix = %wZ\n", &VNetRoot->NamePrefix));
|
|
|
|
InnerPrefixLength = VNetRoot->NamePrefix.Length;
|
|
RxDbgTrace(0, Dbg, ("--> ,IPrefixLen = %08lx\n", InnerPrefixLength));
|
|
|
|
CopyBuffer = VNetRootName->Buffer;
|
|
PreFcbLength = VNetRootName->Length;
|
|
|
|
if (NameConjuringMethod == VNetRoot_As_UNC_Name) {
|
|
// move up past the drive information
|
|
for (;;) {
|
|
CopyBuffer++; PreFcbLength -= sizeof(WCHAR);
|
|
if (PreFcbLength == 0) break;
|
|
if (*CopyBuffer == L'\\') break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FlagOn(Fcb->FcbState,FCB_STATE_ADDEDBACKSLASH)) {
|
|
InnerPrefixLength += sizeof(WCHAR);
|
|
}
|
|
|
|
// next, Copyin the NetRoot Part OR the VNetRoot part.
|
|
// If we overflow, set *pLengthRemaining to -1 as a flag.
|
|
|
|
if (NameConjuringMethod != VNetRoot_As_DriveLetter) {
|
|
|
|
if (*pLengthRemaining < PreFcbLength) {
|
|
|
|
BytesToCopy = *pLengthRemaining;
|
|
*pLengthRemaining = -1;
|
|
|
|
} else {
|
|
|
|
BytesToCopy = PreFcbLength;
|
|
*pLengthRemaining -= BytesToCopy;
|
|
}
|
|
|
|
RtlCopyMemory( OriginalName,
|
|
CopyBuffer,
|
|
BytesToCopy );
|
|
|
|
BytesToCopy2 = BytesToCopy;
|
|
|
|
} else {
|
|
|
|
PreFcbLength = 0;
|
|
BytesToCopy2 = 0;
|
|
|
|
if ((FcbName->Length > InnerPrefixLength)
|
|
&& ( *((PWCHAR)(((PCHAR)FcbName->Buffer)+InnerPrefixLength)) != OBJ_NAME_PATH_SEPARATOR )) {
|
|
InnerPrefixLength -= sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
FcbNameSuffixLength = FcbName->Length - InnerPrefixLength;
|
|
|
|
if (FcbNameSuffixLength <= 0) {
|
|
FcbNameBuffer = L"\\";
|
|
FcbNameSuffixLength = 2;
|
|
InnerPrefixLength = 0;
|
|
} else {
|
|
FcbNameBuffer = FcbName->Buffer;
|
|
}
|
|
|
|
//report how much is really needed
|
|
*pActualNameLength = PreFcbLength + FcbNameSuffixLength;
|
|
|
|
// the netroot part has been copied; finally, copy in the part of the name
|
|
// that is past the prefix
|
|
|
|
if (*pLengthRemaining != -1) {
|
|
|
|
// Next, Copyin the Fcb Part
|
|
// If we overflow, set *pLengthRemaining to -1 as a flag.
|
|
//
|
|
|
|
if (*pLengthRemaining < FcbNameSuffixLength) {
|
|
|
|
BytesToCopy = *pLengthRemaining;
|
|
*pLengthRemaining = -1;
|
|
|
|
} else {
|
|
|
|
BytesToCopy = FcbNameSuffixLength;
|
|
*pLengthRemaining -= BytesToCopy;
|
|
}
|
|
|
|
RtlCopyMemory( ((PCHAR)OriginalName)+PreFcbLength,
|
|
((PCHAR)FcbNameBuffer)+InnerPrefixLength,
|
|
BytesToCopy );
|
|
} else {
|
|
|
|
//DbgPrint("No second copy\n");
|
|
DbgDoit(BytesToCopy=0;);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxConjureOriginalFilename -> VOID\n", 0));
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query name information function. what makes this hard is that
|
|
we have to return partial results.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the name fits
|
|
STATUS_BUFFER_OVERFLOW otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb; RxCaptureFobx;
|
|
PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
|
|
LONG OriginalLengthRemaining = RxContext->Info.LengthRemaining;
|
|
RxDbgTrace(+1, Dbg, ("RxQueryNameInfo...\n", 0));
|
|
RxLog(("RxQueryNameInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryNameInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
*pLengthRemaining -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
|
|
|
|
if (*pLengthRemaining < 0) {
|
|
*pLengthRemaining = 0;
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
} else {
|
|
RxConjureOriginalName(capFcb,capFobx,
|
|
&Buffer->FileNameLength,
|
|
&Buffer->FileName[0],
|
|
pLengthRemaining,
|
|
VNetRoot_As_UNC_Name //VNetRoot_As_DriveLetter
|
|
);
|
|
RxDbgTrace( 0, Dbg, ("*pLengthRemaining = %08lx\n", *pLengthRemaining));
|
|
if (*pLengthRemaining < 0) {
|
|
*pLengthRemaining = 0;
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxQueryNameInfo -> %08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryAlternateNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine queries the short name of the file.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryAlternateNameInfo...\n", 0));
|
|
RxLog(("RxQueryAlternateNameInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryAlternateNameInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileAlternateNameInformation,
|
|
Buffer);
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxQueryAlternateNameInfo...Status %lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryCompressedInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PFILE_COMPRESSION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query compressed file size function for fat.
|
|
This is only defined for compressed volumes.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is to
|
|
be returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryCompressedFileSize...\n", 0));
|
|
RxLog(("RxQueryCompressedFileSize\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryCompressedInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
// Start by flushing the file. We have to do this since the compressed
|
|
// file size is not defined until the file is actually written to disk.
|
|
|
|
Status = RxFlushFcbInSystemCache(capFcb, TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxNormalizeAndRaiseStatus( RxContext, Status );
|
|
}
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FileCompressionInformation,
|
|
Buffer);
|
|
|
|
RxDbgTrace( 0, Dbg, ("LengthRemaining = %08lx\n", RxContext->Info.LengthRemaining));
|
|
RxDbgTrace(-1, Dbg, ("RxQueryCompressedFileSize -> Status\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RxSetPipeInfo(
|
|
IN OUT PRX_CONTEXT RxContext)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine updates the FILE_PIPE_INFORMATION/FILE_PIPE_REMOTE_INFORMATION
|
|
associated with an instance of a named pipe
|
|
|
|
Arguments:
|
|
|
|
RxContext -- the associated RDBSS context
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFobx;
|
|
RxCaptureFcb;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
FILE_INFORMATION_CLASS FileInformationClass = capPARAMS->Parameters.QueryFile.FileInformationClass;
|
|
BOOLEAN PostIrp = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxSetPipeInfo...\n", 0));
|
|
RxLog(("RxSetPipeInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxSetPipeInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
if (capFcb->pNetRoot->Type != NET_ROOT_PIPE) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
switch (FileInformationClass) {
|
|
case FilePipeInformation:
|
|
{
|
|
if (capPARAMS->Parameters.SetFile.Length == sizeof(FILE_PIPE_INFORMATION)) {
|
|
PFILE_PIPE_INFORMATION pPipeInfo = (PFILE_PIPE_INFORMATION)capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
if ((pPipeInfo->ReadMode != capFobx->Specific.NamedPipe.ReadMode) ||
|
|
(pPipeInfo->CompletionMode != capFobx->Specific.NamedPipe.CompletionMode)) {
|
|
RxContext->Info.FileInformationClass = (FilePipeInformation);
|
|
RxContext->Info.Buffer = pPipeInfo;
|
|
RxContext->Info.Length = sizeof(FILE_PIPE_INFORMATION);
|
|
MINIRDR_CALL(Status,RxContext,capFcb->MRxDispatch,MRxSetFileInfo,(RxContext));
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
capFobx->Specific.NamedPipe.ReadMode = pPipeInfo->ReadMode;
|
|
capFobx->Specific.NamedPipe.CompletionMode = pPipeInfo->CompletionMode;
|
|
}
|
|
}
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
break;
|
|
case FilePipeLocalInformation:
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
case FilePipeRemoteInformation:
|
|
{
|
|
if (capPARAMS->Parameters.SetFile.Length == sizeof(FILE_PIPE_REMOTE_INFORMATION)) {
|
|
PFILE_PIPE_REMOTE_INFORMATION pPipeRemoteInfo = (PFILE_PIPE_REMOTE_INFORMATION)capReqPacket->AssociatedIrp.SystemBuffer;
|
|
|
|
capFobx->Specific.NamedPipe.CollectDataTime = pPipeRemoteInfo->CollectDataTime;
|
|
capFobx->Specific.NamedPipe.CollectDataSize = pPipeRemoteInfo->MaximumCollectionCount;
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetPipeInfo: Status ....%lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetSimpleInfo(
|
|
IN OUT PRX_CONTEXT RxContext)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine updates file information that is changed through
|
|
a simple MiniRdr Call.
|
|
Right now this consists of ShortNameInfo & ValdiDataLengthInfo
|
|
|
|
Arguments:
|
|
|
|
RxContext -- the associated RDBSS context
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
RxCaptureParamBlock;
|
|
FILE_INFORMATION_CLASS FileInformationClass = capPARAMS->Parameters.SetFile.FileInformationClass;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
// logging code
|
|
RxDbgTrace(+1, Dbg, ("RxSetSimpleInfo: %d\n", FileInformationClass));
|
|
RxLog(("RxSetSimpleInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxSetSimpleInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
|
|
// call the MiniRdr
|
|
Status = RxpSetInfoMiniRdr(RxContext,FileInformationClass);
|
|
|
|
// logging code
|
|
RxDbgTrace(-1, Dbg, ("RxSetSimpleInfo: Status ....%lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryPipeInfo(
|
|
IN PRX_CONTEXT RxContext,
|
|
IN OUT PVOID pBuffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine queries the FILE_PIPE_INFORMATION/FILE_PIPE_REMOTE_INFORMATION
|
|
and FILE_PIPE_LOCAL_INFORMATION associated with an instance of a named pipe
|
|
|
|
Arguments:
|
|
|
|
RxContext -- the associated RDBSS context
|
|
|
|
pBuffer -- the buffer for query information
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureRequestPacket;
|
|
RxCaptureFcb; RxCaptureFobx;
|
|
RxCaptureParamBlock;
|
|
RxCaptureFileObject;
|
|
|
|
FILE_INFORMATION_CLASS FileInformationClass = capPARAMS->Parameters.QueryFile.FileInformationClass;
|
|
PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
|
|
BOOLEAN PostIrp = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryPipeInfo...\n", 0));
|
|
RxLog(("RxQueryPipeInfo\n"));
|
|
RxWmiLog(LOG,
|
|
RxQueryPipeInfo,
|
|
LOGPTR(RxContext));
|
|
|
|
if (capFcb->pNetRoot->Type != NET_ROOT_PIPE) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
switch (FileInformationClass) {
|
|
case FilePipeInformation:
|
|
if (*pLengthRemaining >= sizeof(FILE_PIPE_INFORMATION)) {
|
|
PFILE_PIPE_INFORMATION pPipeInfo = (PFILE_PIPE_INFORMATION)pBuffer;
|
|
|
|
pPipeInfo->ReadMode = capFobx->Specific.NamedPipe.ReadMode;
|
|
pPipeInfo->CompletionMode = capFobx->Specific.NamedPipe.CompletionMode;
|
|
|
|
// Update the buffer length
|
|
*pLengthRemaining -= sizeof( FILE_PIPE_INFORMATION );
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
case FilePipeLocalInformation:
|
|
if (*pLengthRemaining >= sizeof(FILE_PIPE_LOCAL_INFORMATION)) {
|
|
PFILE_PIPE_LOCAL_INFORMATION pPipeLocalInfo = (PFILE_PIPE_LOCAL_INFORMATION)pBuffer;
|
|
|
|
|
|
Status = RxpQueryInfoMiniRdr(
|
|
RxContext,
|
|
FilePipeLocalInformation,
|
|
pBuffer);
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
case FilePipeRemoteInformation:
|
|
if (*pLengthRemaining >= sizeof(FILE_PIPE_REMOTE_INFORMATION)) {
|
|
PFILE_PIPE_REMOTE_INFORMATION pPipeRemoteInfo = (PFILE_PIPE_REMOTE_INFORMATION)pBuffer;
|
|
|
|
pPipeRemoteInfo->CollectDataTime = capFobx->Specific.NamedPipe.CollectDataTime;
|
|
pPipeRemoteInfo->MaximumCollectionCount = capFobx->Specific.NamedPipe.CollectDataSize;
|
|
|
|
// Update the buffer length
|
|
*pLengthRemaining -= sizeof( FILE_PIPE_REMOTE_INFORMATION );
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
default:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("RxQueryPipeInfo: *pLengthRemaining = %08lx\n", *pLengthRemaining));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|