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.
2819 lines
80 KiB
2819 lines
80 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 PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryStandardInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryInternalInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_INTERNAL_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryEaInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_EA_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryPositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_POSITION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryAlternateNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_NAME_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryCompressedInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_COMPRESSION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
RxQueryPipeInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
IN OUT PVOID PipeInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetBasicInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetDispositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetRenameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetPositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetAllocationInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetEndOfFileInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetPipeInfo(
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
);
|
|
|
|
NTSTATUS
|
|
RxSetSimpleInfo(
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
#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,
|
|
PIRP Irp,
|
|
PFCB Fcb,
|
|
FILE_INFORMATION_CLASS FileInformationClass
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
RxContext->Info.FileInformationClass = FileInformationClass;
|
|
RxContext->Info.Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
RxContext->Info.Length = IrpSp->Parameters.SetFile.Length;
|
|
|
|
MINIRDR_CALL( Status,
|
|
RxContext,
|
|
Fcb->MRxDispatch,
|
|
MRxSetFileInfo,
|
|
(RxContext) );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxpQueryInfoMiniRdr (
|
|
PRX_CONTEXT RxContext,
|
|
PFCB Fcb,
|
|
FILE_INFORMATION_CLASS InformationClass,
|
|
PVOID Buffer)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
RxContext->Info.FileInformationClass = InformationClass;
|
|
RxContext->Info.Buffer = Buffer;
|
|
|
|
MINIRDR_CALL(
|
|
Status,
|
|
RxContext,
|
|
Fcb->MRxDispatch,
|
|
MRxQueryFileInfo,
|
|
(RxContext));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCommonQueryInformation (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
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;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PFCB Fcb;
|
|
PFOBX Fobx;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen;
|
|
PVOID Buffer = NULL;
|
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
|
|
|
BOOLEAN FcbAcquired = FALSE;
|
|
BOOLEAN PostIrp = FALSE;
|
|
|
|
PFILE_ALL_INFORMATION AllInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxCommonQueryInformation...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|
RxContext, Fobx, Fcb) );
|
|
RxDbgTrace( 0, Dbg, (" Buffer %08lx Length %08lx FileInfoClass %08lx\n",
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.QueryFile.Length,
|
|
IrpSp->Parameters.QueryFile.FileInformationClass
|
|
) );
|
|
RxLog(( "QueryFileInfo %lx %lx %lx\n", RxContext, Fcb, Fobx ));
|
|
RxWmiLog( LOG,
|
|
RxCommonQueryInformation_1,
|
|
LOGPTR( RxContext )
|
|
LOGPTR( Fcb )
|
|
LOGPTR( Fobx ) );
|
|
RxLog(( " alsoqfi %lx %lx %ld\n",
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.QueryFile.Length,
|
|
IrpSp->Parameters.QueryFile.FileInformationClass ));
|
|
RxWmiLog( LOG,
|
|
RxCommonQueryInformation_2,
|
|
LOGPTR( Irp->AssociatedIrp.SystemBuffer )
|
|
LOGULONG( IrpSp->Parameters.QueryFile.Length )
|
|
LOGULONG( IrpSp->Parameters.QueryFile.FileInformationClass ) );
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length;
|
|
|
|
try {
|
|
|
|
//
|
|
// Obtain the Request packet's(user's) buffer
|
|
//
|
|
|
|
Buffer = RxMapSystemBuffer( RxContext, Irp );
|
|
|
|
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( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
|
|
if (FileInformationClass != FileNameInformation) {
|
|
|
|
//
|
|
// If this is FileCompressedFileSize, we need the Fcb
|
|
// exclusive.
|
|
//
|
|
|
|
if (FileInformationClass != FileCompressionInformation) {
|
|
Status = RxAcquireSharedFcb( RxContext, Fcb );
|
|
} else {
|
|
Status = RxAcquireExclusiveFcb( RxContext, Fcb );
|
|
}
|
|
|
|
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)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, BasicInformation );
|
|
|
|
Status = RxQueryBasicInfo( RxContext, Irp, Fcb, &AllInfo->BasicInformation );
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, StandardInformation );
|
|
|
|
Status = RxQueryStandardInfo( RxContext, Irp, Fcb, Fobx, &AllInfo->StandardInformation );
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, InternalInformation );
|
|
|
|
Status = RxQueryInternalInfo( RxContext, Irp, Fcb, &AllInfo->InternalInformation );
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, EaInformation );
|
|
|
|
Status = RxQueryEaInfo( RxContext, Irp, Fcb, &AllInfo->EaInformation );
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, PositionInformation );
|
|
|
|
Status = RxQueryPositionInfo( RxContext, Irp, Fcb, &AllInfo->PositionInformation );
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
RxContext->Info.LengthRemaining = (LONG)IrpSp->Parameters.QueryFile.Length - FIELD_OFFSET( FILE_ALL_INFORMATION, NameInformation );
|
|
|
|
//
|
|
// QueryNameInfo could return buffer-overflow!!!
|
|
//
|
|
|
|
Status = RxQueryNameInfo( RxContext, Irp, Fcb, Fobx, &AllInfo->NameInformation );
|
|
break;
|
|
|
|
case FileBasicInformation:
|
|
|
|
Status = RxQueryBasicInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FileStandardInformation:
|
|
|
|
Status = RxQueryStandardInfo( RxContext, Irp, Fcb, Fobx, Buffer );
|
|
break;
|
|
|
|
case FileInternalInformation:
|
|
|
|
Status = RxQueryInternalInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FileEaInformation:
|
|
|
|
Status = RxQueryEaInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
Status = RxQueryPositionInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FileNameInformation:
|
|
|
|
Status = RxQueryNameInfo( RxContext, Irp, Fcb, Fobx, Buffer );
|
|
break;
|
|
|
|
case FileAlternateNameInformation:
|
|
|
|
Status = RxQueryAlternateNameInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FileCompressionInformation:
|
|
|
|
Status = RxQueryCompressedInfo( RxContext, Irp, Fcb, Buffer );
|
|
break;
|
|
|
|
case FilePipeInformation:
|
|
case FilePipeLocalInformation:
|
|
case FilePipeRemoteInformation:
|
|
|
|
Status = RxQueryPipeInfo( RxContext, Irp, Fcb, Fobx, Buffer );
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// anything that we don't understand, we just remote
|
|
//
|
|
|
|
RxContext->StoredStatus = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
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 = IrpSp->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"
|
|
//
|
|
|
|
Irp->IoStatus.Information = IrpSp->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, Fcb );
|
|
}
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxCommonQueryInformation -> %08lx\n", Status) );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCommonSetInformation (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
NODE_TYPE_CODE TypeOfOpen;
|
|
PFCB Fcb;
|
|
PFOBX Fobx;
|
|
PNET_ROOT NetRoot;
|
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
|
PFCB TempFcb;
|
|
|
|
PFILE_DISPOSITION_INFORMATION Buffer;
|
|
|
|
BOOLEAN Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
|
|
BOOLEAN FcbAcquired = FALSE;
|
|
BOOLEAN NetRootTableLockAcquired = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
TypeOfOpen = RxDecodeFileObject( IrpSp->FileObject, &Fcb, &Fobx );
|
|
NetRoot = Fcb->NetRoot;
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxCommonSetInformation...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|
RxContext, Fobx, Fcb) );
|
|
RxDbgTrace( 0, Dbg, (" Buffer %08lx Length %08lx FileInfoClass %08lx Replace %08lx\n",
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.QueryFile.Length,
|
|
IrpSp->Parameters.QueryFile.FileInformationClass,
|
|
IrpSp->Parameters.SetFile.ReplaceIfExists
|
|
) );
|
|
|
|
RxLog(( "SetFileInfo %lx %lx %lx\n", RxContext, Fcb, Fobx ));
|
|
RxWmiLog( LOG,
|
|
RxCommonSetInformation_1,
|
|
LOGPTR( RxContext )
|
|
LOGPTR( Fcb )
|
|
LOGPTR( Fobx ) );
|
|
RxLog((" alsosfi %lx %lx %ld %lx\n",
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.QueryFile.Length,
|
|
IrpSp->Parameters.QueryFile.FileInformationClass,
|
|
IrpSp->Parameters.SetFile.ReplaceIfExists ));
|
|
RxWmiLog( LOG,
|
|
RxCommonSetInformation_2,
|
|
LOGPTR(Irp->AssociatedIrp.SystemBuffer)
|
|
LOGULONG( IrpSp->Parameters.QueryFile.Length )
|
|
LOGULONG( IrpSp->Parameters.QueryFile.FileInformationClass )
|
|
LOGUCHAR( IrpSp->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:
|
|
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 );
|
|
}
|
|
|
|
//
|
|
// 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) &&
|
|
(IrpSp->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)) {
|
|
|
|
//
|
|
// For directory renames, all files under that directory need to be closed.
|
|
// So, we purge all files on the netroot (share) in case this is a directory.
|
|
//
|
|
|
|
if ( NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY ) {
|
|
TempFcb = NULL;
|
|
} else {
|
|
TempFcb = Fcb;
|
|
}
|
|
|
|
RxPurgeRelatedFobxs( NetRoot,
|
|
RxContext,
|
|
ATTEMPT_FINALIZE_ON_PURGE,
|
|
TempFcb );
|
|
|
|
RxScavengeFobxsForNetRoot( NetRoot, TempFcb );
|
|
|
|
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( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
|
|
Status = RxAcquireExclusiveFcb( RxContext, Fcb );
|
|
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, Irp, Fcb, Fobx );
|
|
break;
|
|
|
|
case FileDispositionInformation:
|
|
|
|
Buffer = Irp->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( &Fcb->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( Fcb );
|
|
|
|
RxReleaseFcbTableLock( &NetRoot->FcbTable );
|
|
NetRootTableLockAcquired = FALSE;
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = RxSetDispositionInfo( RxContext, Irp, Fcb );
|
|
}
|
|
|
|
break;
|
|
|
|
case FileMoveClusterInformation:
|
|
case FileLinkInformation:
|
|
case FileRenameInformation:
|
|
|
|
//
|
|
// We proceed with this operation only if we can wait
|
|
//
|
|
|
|
if (!Wait) {
|
|
|
|
Status = RxFsdPostRequest( RxContext );
|
|
|
|
} else {
|
|
|
|
ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
|
|
|
|
Status = RxSetRenameInfo( RxContext, Irp, Fcb, Fobx );
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(FileInformationClass == FileRenameInformation)) {
|
|
|
|
ASSERT( FcbAcquired && NetRootTableLockAcquired );
|
|
|
|
RxRemoveNameNetFcb( Fcb );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
Status = RxSetPositionInfo( RxContext, Irp, Fcb, Fobx );
|
|
break;
|
|
|
|
|
|
case FileAllocationInformation:
|
|
|
|
Status = RxSetAllocationInfo( RxContext, Irp, Fcb, Fobx );
|
|
break;
|
|
|
|
case FileEndOfFileInformation:
|
|
|
|
Status = RxSetEndOfFileInfo( RxContext, Irp, Fcb, Fobx );
|
|
break;
|
|
|
|
case FilePipeInformation:
|
|
case FilePipeLocalInformation:
|
|
case FilePipeRemoteInformation:
|
|
|
|
Status = RxSetPipeInfo( RxContext, Irp, Fcb, Fobx );
|
|
break;
|
|
|
|
case FileValidDataLengthInformation:
|
|
|
|
if(!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers, NULL )) {
|
|
|
|
Status = STATUS_USER_MAPPED_FILE;
|
|
break;
|
|
}
|
|
Status = RxSetSimpleInfo( RxContext, Irp, Fcb );
|
|
break;
|
|
|
|
case FileShortNameInformation:
|
|
|
|
Status = RxSetSimpleInfo( RxContext, Irp, Fcb );
|
|
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, Fcb );
|
|
}
|
|
|
|
if (NetRootTableLockAcquired) {
|
|
RxReleaseFcbTableLock( &NetRoot->FcbTable );
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxCommonSetInformation -> %08lx\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetBasicInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PFILE_BASIC_INFORMATION Buffer;
|
|
|
|
BOOLEAN ModifyCreation = FALSE;
|
|
BOOLEAN ModifyLastAccess = FALSE;
|
|
BOOLEAN ModifyLastWrite = FALSE;
|
|
BOOLEAN ModifyLastChange = FALSE;
|
|
|
|
|
|
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, Irp, Fcb, 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 = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
try {
|
|
|
|
//
|
|
// Check if the user specified a non-zero creation time
|
|
//
|
|
|
|
if (Buffer->CreationTime.QuadPart != 0 ) {
|
|
ModifyCreation = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check if the user specified a non-zero last access time
|
|
//
|
|
|
|
if (Buffer->LastAccessTime.QuadPart != 0 ) {
|
|
ModifyLastAccess = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check if the user specified a non-zero last write time
|
|
//
|
|
|
|
if (Buffer->LastWriteTime.QuadPart != 0 ) {
|
|
ModifyLastWrite = TRUE;
|
|
}
|
|
|
|
|
|
if (Buffer->ChangeTime.QuadPart != 0 ) {
|
|
ModifyLastChange = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if the user specified a non zero file attributes byte
|
|
//
|
|
|
|
if (Buffer->FileAttributes != 0) {
|
|
|
|
USHORT Attributes;
|
|
|
|
//
|
|
// Remove the normal attribute flag
|
|
//
|
|
|
|
Attributes = (USHORT)FlagOn( 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( Fcb ) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) {
|
|
|
|
ClearFlag( Attributes, FILE_ATTRIBUTE_DIRECTORY );
|
|
|
|
} else {
|
|
|
|
SetFlag( Attributes, FILE_ATTRIBUTE_DIRECTORY );
|
|
}
|
|
|
|
//
|
|
// Mark the FcbState temporary flag correctly.
|
|
//
|
|
|
|
if (FlagOn( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY )) {
|
|
|
|
SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
|
|
SetFlag( FileObject->Flags, FO_TEMPORARY_FILE );
|
|
|
|
} else {
|
|
|
|
ClearFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
|
|
ClearFlag( FileObject->Flags, FO_TEMPORARY_FILE );
|
|
}
|
|
|
|
//
|
|
// Set the new attributes byte, and mark the bcb dirty
|
|
//
|
|
|
|
Fcb->Attributes = Attributes;
|
|
}
|
|
|
|
if (ModifyCreation) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
Fcb->CreationTime = Buffer->CreationTime;
|
|
|
|
//
|
|
// Now because the user just set the creation time we
|
|
// better not set the creation time on close
|
|
//
|
|
|
|
SetFlag( Fobx->Flags, FOBX_FLAG_USER_SET_CREATION );
|
|
}
|
|
|
|
if (ModifyLastAccess) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
Fcb->LastAccessTime = Buffer->LastAccessTime;
|
|
|
|
//
|
|
// Now because the user just set the last access time we
|
|
// better not set the last access time on close
|
|
//
|
|
|
|
SetFlag( Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS );
|
|
}
|
|
|
|
if (ModifyLastWrite) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
Fcb->LastWriteTime = Buffer->LastWriteTime;
|
|
|
|
//
|
|
// Now because the user just set the last write time we
|
|
// better not set the last write time on close
|
|
//
|
|
|
|
SetFlag( Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE );
|
|
}
|
|
|
|
if (ModifyLastChange) {
|
|
|
|
//
|
|
// Set the new last write time in the dirent, and mark
|
|
// the bcb dirty
|
|
//
|
|
|
|
Fcb->LastChangeTime = Buffer->ChangeTime;
|
|
|
|
//
|
|
// Now because the user just set the last write time we
|
|
// better not set the last write time on close
|
|
//
|
|
|
|
SetFlag( Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE );
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugUnwind( RxSetBasicInfo );
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxSetBasicInfo -> %08lx\n", Status) );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetDispositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
|
|
PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
|
|
PFILE_DISPOSITION_INFORMATION Buffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxSetDispositionInfo...\n", 0) );
|
|
RxLog(( "RxSetDispositionInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxSetDispositionInfo,
|
|
LOGPTR( RxContext ) );
|
|
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// call down and check for success
|
|
//
|
|
|
|
Status = RxpSetInfoMiniRdr( RxContext, Irp, Fcb, 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) {
|
|
|
|
SetFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
|
|
FileObject->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));
|
|
|
|
ClearFlag(Fcb->FcbState, ~FCB_STATE_DELETE_ON_CLOSE );
|
|
FileObject->DeletePending = FALSE;
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetDispositionInfo -> RxStatus(SUCCESS)\n", 0));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetRenameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxSetRenameInfo ......FileObj = %08lx\n",
|
|
IrpSp->Parameters.SetFile.FileObject) );
|
|
RxLog(("RxSetRenameInfo %lx %lx\n",
|
|
IrpSp->Parameters.SetFile.FileObject,
|
|
IrpSp->Parameters.SetFile.ReplaceIfExists ));
|
|
RxWmiLog(LOG,
|
|
RxSetRenameInfo,
|
|
LOGPTR(IrpSp->Parameters.SetFile.FileObject)
|
|
LOGUCHAR(IrpSp->Parameters.SetFile.ReplaceIfExists));
|
|
|
|
RxContext->Info.ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
|
|
if (IrpSp->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 = IrpSp->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),
|
|
Fcb->NetRoot->DiskParameters.RenameInfoOverallocationSize));
|
|
if (RenameFcb->NetRoot != Fcb->NetRoot) {
|
|
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
|
|
+ Fcb->NetRoot->DiskParameters.RenameInfoOverallocationSize;
|
|
RxDbgTrace(0, Dbg, ("-->AllocSize is %08lx\n", allocate_size));
|
|
RenameInformation = RxAllocatePool( PagedPool, allocate_size );
|
|
if (RenameInformation != NULL) {
|
|
try {
|
|
*RenameInformation = *((PFILE_RENAME_INFORMATION)(Irp->AssociatedIrp.SystemBuffer));
|
|
RenameInformation->FileNameLength = RenameFcb->FcbTableEntry.Path.Length;
|
|
|
|
RtlMoveMemory(
|
|
&RenameInformation->FileName[0],
|
|
RenameFcb->FcbTableEntry.Path.Buffer,
|
|
RenameFcb->FcbTableEntry.Path.Length);
|
|
|
|
RxContext->Info.FileInformationClass = (IrpSp->Parameters.SetFile.FileInformationClass);
|
|
RxContext->Info.Buffer = RenameInformation;
|
|
RxContext->Info.Length = allocate_size;
|
|
MINIRDR_CALL(Status,RxContext,Fcb->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,
|
|
Irp,
|
|
Fcb,
|
|
IrpSp->Parameters.SetFile.FileInformationClass );
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetRenameInfo -> %08lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetPositionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
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 to the minirdrs .........
|
|
//
|
|
|
|
Buffer = Irp->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( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
DeviceObject = IrpSp->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));
|
|
|
|
FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetPositionInfo -> %08lx\n", STATUS_SUCCESS));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetAllocationInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PFILE_ALLOCATION_INFORMATION Buffer;
|
|
|
|
LONGLONG NewAllocationSize;
|
|
|
|
BOOLEAN CacheMapInitialized = FALSE;
|
|
LARGE_INTEGER OriginalFileSize;
|
|
LARGE_INTEGER OriginalAllocationSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
NewAllocationSize = Buffer->AllocationSize.QuadPart;
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxSetAllocationInfo.. to %08lx\n", NewAllocationSize) );
|
|
RxLog(( "SetAlloc %lx %lx %lx\n", Fcb->Header.FileSize.LowPart,
|
|
(ULONG)NewAllocationSize, Fcb->Header.AllocationSize.LowPart ));
|
|
RxWmiLog( LOG,
|
|
RxSetAllocationInfo_1,
|
|
LOGULONG( Fcb->Header.FileSize.LowPart )
|
|
LOGULONG( (ULONG)NewAllocationSize )
|
|
LOGULONG( Fcb->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 ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
|
|
(FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
|
|
(Irp->RequestorMode != KernelMode)) {
|
|
|
|
if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
|
|
return STATUS_FILE_CLOSED;
|
|
}
|
|
|
|
RxAdjustAllocationSizeforCC( Fcb );
|
|
|
|
//
|
|
// Now initialize the cache map.
|
|
//
|
|
|
|
CcInitializeCacheMap( FileObject,
|
|
(PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
|
|
FALSE,
|
|
&RxData.CacheManagerCallbacks,
|
|
Fcb );
|
|
|
|
CacheMapInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Now mark that the time on the dirent needs to be updated on close.
|
|
//
|
|
|
|
SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
|
|
|
|
try {
|
|
|
|
//
|
|
// Check here if we will be decreasing file size and synchonize with
|
|
// paging IO.
|
|
//
|
|
|
|
RxGetFileSizeWithLock( Fcb, &OriginalFileSize.QuadPart );
|
|
|
|
if (OriginalFileSize.QuadPart > Buffer->AllocationSize.QuadPart) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
|
|
&Buffer->AllocationSize )) {
|
|
|
|
try_return( Status = STATUS_USER_MAPPED_FILE );
|
|
}
|
|
|
|
|
|
RxAcquirePagingIoResource( RxContext, Fcb );
|
|
|
|
RxSetFileSizeWithLock( Fcb, &NewAllocationSize );
|
|
|
|
//
|
|
// If we reduced the file size to less than the ValidDataLength,
|
|
// adjust the VDL.
|
|
//
|
|
|
|
if (Fcb->Header.ValidDataLength.QuadPart > NewAllocationSize) {
|
|
|
|
Fcb->Header.ValidDataLength.QuadPart = NewAllocationSize;
|
|
}
|
|
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
}
|
|
|
|
OriginalAllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
|
|
Fcb->Header.AllocationSize.QuadPart = NewAllocationSize;
|
|
|
|
Status = RxpSetInfoMiniRdr( RxContext,
|
|
Irp,
|
|
Fcb,
|
|
FileAllocationInformation );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
|
|
Fcb->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( FileObject, (PCC_FILE_SIZES)&Fcb->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.
|
|
//
|
|
|
|
Fcb->Header.AllocationSize.QuadPart = OriginalAllocationSize.QuadPart;
|
|
|
|
RxpSetInfoMiniRdr( RxContext,
|
|
Irp,
|
|
Fcb,
|
|
FileAllocationInformation );
|
|
|
|
try_return( Status );
|
|
}
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
} finally {
|
|
|
|
if (CacheMapInitialized) {
|
|
CcUninitializeCacheMap( FileObject, NULL, NULL );
|
|
}
|
|
}
|
|
|
|
RxLog(( "SetAllocExit %lx %lx\n",
|
|
Fcb->Header.FileSize.LowPart,
|
|
Fcb->Header.AllocationSize.LowPart ));
|
|
RxWmiLog( LOG,
|
|
RxSetAllocationInfo_2,
|
|
LOGULONG( Fcb->Header.FileSize.LowPart )
|
|
LOGULONG( Fcb->Header.AllocationSize.LowPart) );
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxSetAllocationInfo -> %08lx\n", STATUS_SUCCESS) );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxSetEndOfFileInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
/*++
|
|
|
|
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 - The rxcontext for the request
|
|
|
|
Irp - irp to proccess
|
|
|
|
Fcb - the fcb to work on
|
|
|
|
Fobx - The fobx for the open
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The result of this operation if it completes without
|
|
an exception.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
PFILE_END_OF_FILE_INFORMATION Buffer;
|
|
|
|
LONGLONG NewFileSize;
|
|
LONGLONG OriginalFileSize;
|
|
LONGLONG OriginalAllocationSize;
|
|
LONGLONG OriginalValidDataLength;
|
|
|
|
BOOLEAN CacheMapInitialized = FALSE;
|
|
BOOLEAN PagingIoResourceAcquired = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
NewFileSize = Buffer->EndOfFile.QuadPart;
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxSetEndOfFileInfo...Old,New,Alloc %08lx,%08lx,%08lx\n",
|
|
Fcb->Header.FileSize.LowPart,
|
|
(ULONG)NewFileSize,
|
|
Fcb->Header.AllocationSize.LowPart) );
|
|
RxLog(( "SetEof %lx %lx %lx %lx\n", RxContext, Fcb->Header.FileSize.LowPart, (ULONG)NewFileSize, Fcb->Header.AllocationSize.LowPart ));
|
|
RxWmiLog( LOG,
|
|
RxSetEndOfFileInfo_1,
|
|
LOGPTR(RxContext)
|
|
LOGULONG( Fcb->Header.FileSize.LowPart )
|
|
LOGULONG( (ULONG)NewFileSize )
|
|
LOGULONG( Fcb->Header.AllocationSize.LowPart ) );
|
|
|
|
//
|
|
// File Size changes are only allowed on a file and not a directory
|
|
//
|
|
|
|
if (NodeType(Fcb) != 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 = Fcb->Header.FileSize.QuadPart;
|
|
OriginalAllocationSize = Fcb->Header.AllocationSize.QuadPart;
|
|
OriginalValidDataLength = Fcb->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 ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
|
|
(FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
|
|
(Irp->RequestorMode != KernelMode)) {
|
|
|
|
if ( FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ) {
|
|
try_return( STATUS_FILE_CLOSED );
|
|
}
|
|
|
|
RxAdjustAllocationSizeforCC( Fcb );
|
|
|
|
//
|
|
// Now initialize the cache map.
|
|
//
|
|
|
|
CcInitializeCacheMap( FileObject,
|
|
(PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
|
|
FALSE,
|
|
&RxData.CacheManagerCallbacks,
|
|
Fcb );
|
|
|
|
CacheMapInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// RDR doesn't handle the lazy write of file sizes. See abovein RxCommonSetInformation
|
|
//
|
|
|
|
ASSERTMSG( "Unhandled advance only EOF\n", !IrpSp->Parameters.SetFile.AdvanceOnly );
|
|
|
|
//
|
|
// Check if we are really changing the file size
|
|
//
|
|
|
|
if (Fcb->Header.FileSize.QuadPart != NewFileSize) {
|
|
|
|
if (NewFileSize < Fcb->Header.FileSize.QuadPart) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( FileObject->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( RxContext, Fcb );
|
|
|
|
//
|
|
// Set the new file size
|
|
//
|
|
|
|
Fcb->Header.FileSize.QuadPart = NewFileSize;
|
|
|
|
//
|
|
// If we reduced the file size to less than the ValidDataLength,
|
|
// adjust the VDL.
|
|
//
|
|
|
|
if (Fcb->Header.ValidDataLength.QuadPart > NewFileSize) {
|
|
Fcb->Header.ValidDataLength.QuadPart = NewFileSize;
|
|
}
|
|
|
|
//
|
|
// Change the file allocation size as well
|
|
//
|
|
|
|
Fcb->Header.AllocationSize.QuadPart = NewFileSize;
|
|
|
|
Status = RxpSetInfoMiniRdr( RxContext,
|
|
Irp,
|
|
Fcb,
|
|
FileEndOfFileInformation );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
if (PagingIoResourceAcquired) {
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
PagingIoResourceAcquired = FALSE;
|
|
}
|
|
|
|
//
|
|
// We must now update the cache mapping (benign if not cached).
|
|
//
|
|
|
|
try {
|
|
|
|
CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
try_return( Status );
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Set our return status to success
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set this handle as having modified the file
|
|
//
|
|
|
|
SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
DebugUnwind( RxSetEndOfFileInfo );
|
|
|
|
if ((AbnormalTermination() || !NT_SUCCESS( Status ))) {
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxSetEndOfFileInfo2 status -> %08lx\n", Status) );
|
|
|
|
Fcb->Header.FileSize.QuadPart = OriginalFileSize;
|
|
Fcb->Header.AllocationSize.QuadPart = OriginalAllocationSize;
|
|
Fcb->Header.ValidDataLength.QuadPart = OriginalValidDataLength;
|
|
|
|
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
|
|
*CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
|
|
}
|
|
|
|
RxLog(("SetEofabnormalorbadstatus %lx %lx", RxContext,Status));
|
|
RxWmiLog( LOG,
|
|
RxSetEndOfFileInfo_3,
|
|
LOGPTR( RxContext )
|
|
LOGULONG( Status ) );
|
|
}
|
|
|
|
if (PagingIoResourceAcquired) {
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
}
|
|
|
|
if (CacheMapInitialized) {
|
|
CcUninitializeCacheMap( FileObject, NULL, NULL );
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetEndOfFileInfo -> %08lx\n", Status));
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
RxLog(( "SetEofexit %lx %lx %lx\n",
|
|
Fcb->Header.FileSize.LowPart,
|
|
(ULONG)NewFileSize,
|
|
Fcb->Header.AllocationSize.LowPart ));
|
|
|
|
RxWmiLog( LOG,
|
|
RxSetEndOfFileInfo_4,
|
|
LOGPTR( RxContext )
|
|
LOGULONG( Fcb->Header.FileSize.LowPart )
|
|
LOGULONG( (ULONG)NewFileSize )
|
|
LOGULONG( Fcb->Header.AllocationSize.LowPart ) );
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN RxForceQFIPassThrough = FALSE;
|
|
|
|
NTSTATUS
|
|
RxQueryBasicInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the query basic information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext -
|
|
|
|
Irp -
|
|
|
|
Fcb -
|
|
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
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,
|
|
Fcb,
|
|
FileBasicInformation,
|
|
Buffer );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryStandardInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query standard information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext -
|
|
|
|
Irp -
|
|
|
|
Fcb -
|
|
|
|
Fobx -
|
|
|
|
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;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
PMRX_SRV_OPEN SrvOpen;
|
|
|
|
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 ) );
|
|
|
|
SrvOpen = Fobx->pSrvOpen;
|
|
|
|
switch (NodeType( Fcb )) {
|
|
|
|
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( SrvOpen->CreateOptions,FILE_OPEN_FOR_BACKUP_INTENT )) {
|
|
|
|
//
|
|
// copy in all the stuff that we know....it may be enough.....
|
|
//
|
|
|
|
Buffer->NumberOfLinks = Fcb->NumberOfLinks;
|
|
Buffer->DeletePending = BooleanFlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
|
|
Buffer->Directory = (NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY);
|
|
|
|
if (Buffer->NumberOfLinks == 0) {
|
|
|
|
//
|
|
// This switch is required because of compatibility reasons with
|
|
// the old redirector.
|
|
//
|
|
|
|
Buffer->NumberOfLinks = 1;
|
|
}
|
|
|
|
if (NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_FILE) {
|
|
|
|
Buffer->AllocationSize = Fcb->Header.AllocationSize;
|
|
RxGetFileSizeWithLock( Fcb, &Buffer->EndOfFile.QuadPart );
|
|
}
|
|
|
|
if (!RxForceQFIPassThrough &&
|
|
FlagOn( Fcb->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,
|
|
Fcb,
|
|
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 PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_INTERNAL_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
(Internal Support Routine)
|
|
This routine performs the query internal information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext -
|
|
|
|
Irp -
|
|
|
|
Fcb -
|
|
|
|
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;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxQueryInternalInfo...\n", 0) );
|
|
RxLog(( "RxQueryInternalInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryInternalInfo,
|
|
LOGPTR( RxContext ) );
|
|
|
|
Status = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
FileInternalInformation,
|
|
Buffer );
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxQueryInternalInfo...Status %lx\n", Status) );
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER( Irp );
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryEaInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_EA_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query Ea information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext -
|
|
|
|
Irp -
|
|
|
|
Fcb -
|
|
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxQueryEaInfo...\n", 0));
|
|
RxLog(( "RxQueryEaInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryEaInfo,
|
|
LOGPTR( RxContext ));
|
|
|
|
Status = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
FileEaInformation,
|
|
Buffer );
|
|
|
|
if ((IrpSp->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 PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN OUT PFILE_POSITION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine performs the query position information function for fat.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Irp -
|
|
|
|
Fcb -
|
|
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxQueryPositionInfo...\n", 0) );
|
|
RxLog(( "RxQueryPositionInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryPositionInfo,
|
|
LOGPTR( RxContext ) );
|
|
|
|
Buffer->CurrentByteOffset = FileObject->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;
|
|
|
|
UNREFERENCED_PARAMETER( Irp );
|
|
}
|
|
|
|
VOID
|
|
RxConjureOriginalName (
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
OUT PLONG ActualNameLength,
|
|
IN PWCHAR OriginalName,
|
|
IN OUT PLONG LengthRemaining,
|
|
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
|
|
|
|
ActualNameLength - 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
|
|
|
|
LengthRemaining - 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 = Fcb->NetRoot;
|
|
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 *LengthRemaining to -1 as a flag.
|
|
//
|
|
|
|
if (NameConjuringMethod != VNetRoot_As_DriveLetter) {
|
|
|
|
if (*LengthRemaining < PreFcbLength) {
|
|
|
|
BytesToCopy = *LengthRemaining;
|
|
*LengthRemaining = -1;
|
|
|
|
} else {
|
|
|
|
BytesToCopy = PreFcbLength;
|
|
*LengthRemaining -= BytesToCopy;
|
|
}
|
|
|
|
RtlCopyMemory( OriginalName,
|
|
CopyBuffer,
|
|
BytesToCopy );
|
|
|
|
BytesToCopy2 = BytesToCopy;
|
|
|
|
} else {
|
|
|
|
PreFcbLength = 0;
|
|
BytesToCopy2 = 0;
|
|
|
|
if ((FcbName->Length > InnerPrefixLength) &&
|
|
(*((PWCHAR)Add2Ptr( 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
|
|
//
|
|
|
|
*ActualNameLength = PreFcbLength + FcbNameSuffixLength;
|
|
|
|
//
|
|
// the netroot part has been copied; finally, copy in the part of the name
|
|
// that is past the prefix
|
|
//
|
|
|
|
if (*LengthRemaining != -1) {
|
|
|
|
//
|
|
// Next, Copyin the Fcb Part
|
|
// If we overflow, set *LengthRemaining to -1 as a flag.
|
|
//
|
|
|
|
if (*LengthRemaining < FcbNameSuffixLength) {
|
|
|
|
BytesToCopy = *LengthRemaining;
|
|
*LengthRemaining = -1;
|
|
|
|
} else {
|
|
|
|
BytesToCopy = FcbNameSuffixLength;
|
|
*LengthRemaining -= BytesToCopy;
|
|
}
|
|
|
|
RtlCopyMemory( Add2Ptr( OriginalName, PreFcbLength ),
|
|
Add2Ptr( 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 PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
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;
|
|
|
|
PLONG LengthRemaining = &RxContext->Info.LengthRemaining;
|
|
LONG OriginalLengthRemaining = RxContext->Info.LengthRemaining;
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxQueryNameInfo...\n", 0) );
|
|
RxLog(( "RxQueryNameInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryNameInfo,
|
|
LOGPTR( RxContext ) );
|
|
|
|
PAGED_CODE();
|
|
|
|
*LengthRemaining -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
|
|
|
|
if (*LengthRemaining < 0) {
|
|
*LengthRemaining = 0;
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
} else {
|
|
|
|
RxConjureOriginalName( Fcb,
|
|
Fobx,
|
|
&Buffer->FileNameLength,
|
|
&Buffer->FileName[0],
|
|
LengthRemaining,
|
|
VNetRoot_As_UNC_Name );
|
|
|
|
RxDbgTrace( 0, Dbg, ("*LengthRemaining = %08lx\n", *LengthRemaining) );
|
|
if (*LengthRemaining < 0) {
|
|
|
|
*LengthRemaining = 0;
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxQueryNameInfo -> %08lx\n", Status) );
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER( Irp );
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryAlternateNameInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
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;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxQueryAlternateNameInfo...\n", 0) );
|
|
RxLog(( "RxQueryAlternateNameInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryAlternateNameInfo,
|
|
LOGPTR( RxContext ));
|
|
|
|
Status = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
FileAlternateNameInformation,
|
|
Buffer );
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxQueryAlternateNameInfo...Status %lx\n", Status) );
|
|
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER( Irp );
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryCompressedInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
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;
|
|
|
|
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( Fcb, TRUE );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
RxNormalizeAndRaiseStatus( RxContext, Status );
|
|
}
|
|
|
|
Status = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
FileCompressionInformation,
|
|
Buffer );
|
|
|
|
RxDbgTrace( 0, Dbg, ("LengthRemaining = %08lx\n", RxContext->Info.LengthRemaining) );
|
|
RxDbgTrace( -1, Dbg, ("RxQueryCompressedFileSize -> Status\n", Status) );
|
|
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER( Irp );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxSetPipeInfo (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx
|
|
)
|
|
/*++
|
|
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;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxSetPipeInfo...\n", 0) );
|
|
RxLog(( "RxSetPipeInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxSetPipeInfo,
|
|
LOGPTR( RxContext ));
|
|
|
|
if (Fcb->NetRoot->Type != NET_ROOT_PIPE) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
switch (FileInformationClass) {
|
|
case FilePipeInformation:
|
|
|
|
if (IrpSp->Parameters.SetFile.Length == sizeof(FILE_PIPE_INFORMATION)) {
|
|
|
|
PFILE_PIPE_INFORMATION PipeInfo = (PFILE_PIPE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if ((PipeInfo->ReadMode != Fobx->Specific.NamedPipe.ReadMode) ||
|
|
(PipeInfo->CompletionMode != Fobx->Specific.NamedPipe.CompletionMode)) {
|
|
|
|
RxContext->Info.FileInformationClass = (FilePipeInformation);
|
|
RxContext->Info.Buffer = PipeInfo;
|
|
RxContext->Info.Length = sizeof(FILE_PIPE_INFORMATION);
|
|
|
|
MINIRDR_CALL( Status,
|
|
RxContext,
|
|
Fcb->MRxDispatch,
|
|
MRxSetFileInfo,
|
|
(RxContext) );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Fobx->Specific.NamedPipe.ReadMode = PipeInfo->ReadMode;
|
|
Fobx->Specific.NamedPipe.CompletionMode = PipeInfo->CompletionMode;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
break;
|
|
|
|
case FilePipeLocalInformation:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
case FilePipeRemoteInformation:
|
|
if (IrpSp->Parameters.SetFile.Length == sizeof(FILE_PIPE_REMOTE_INFORMATION)) {
|
|
|
|
PFILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo = (PFILE_PIPE_REMOTE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Fobx->Specific.NamedPipe.CollectDataTime = PipeRemoteInfo->CollectDataTime;
|
|
Fobx->Specific.NamedPipe.CollectDataSize = PipeRemoteInfo->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,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
)
|
|
/*++
|
|
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
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->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, Irp, Fcb, FileInformationClass );
|
|
|
|
//
|
|
// logging code
|
|
//
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxSetSimpleInfo: Status ....%lx\n", Status) );
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxQueryPipeInfo(
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PFOBX Fobx,
|
|
IN OUT PVOID Buffer
|
|
)
|
|
/*++
|
|
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
|
|
|
|
Buffer -- the buffer for query information
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS/STATUS_PENDING or an appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
|
PLONG LengthRemaining = &RxContext->Info.LengthRemaining;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxQueryPipeInfo...\n", 0) );
|
|
RxLog(( "RxQueryPipeInfo\n" ));
|
|
RxWmiLog( LOG,
|
|
RxQueryPipeInfo,
|
|
LOGPTR( RxContext ) );
|
|
|
|
if (Fcb->NetRoot->Type != NET_ROOT_PIPE) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
switch (FileInformationClass) {
|
|
case FilePipeInformation:
|
|
|
|
if (*LengthRemaining >= sizeof(FILE_PIPE_INFORMATION)) {
|
|
|
|
PFILE_PIPE_INFORMATION PipeInfo = (PFILE_PIPE_INFORMATION)Buffer;
|
|
|
|
PipeInfo->ReadMode = Fobx->Specific.NamedPipe.ReadMode;
|
|
PipeInfo->CompletionMode = Fobx->Specific.NamedPipe.CompletionMode;
|
|
|
|
//
|
|
// Update the buffer length
|
|
//
|
|
|
|
*LengthRemaining -= sizeof( FILE_PIPE_INFORMATION );
|
|
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
case FilePipeLocalInformation:
|
|
|
|
if (*LengthRemaining >= sizeof( FILE_PIPE_LOCAL_INFORMATION )) {
|
|
|
|
PFILE_PIPE_LOCAL_INFORMATION pPipeLocalInfo = (PFILE_PIPE_LOCAL_INFORMATION)Buffer;
|
|
|
|
Status = RxpQueryInfoMiniRdr( RxContext,
|
|
Fcb,
|
|
FilePipeLocalInformation,
|
|
Buffer );
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
case FilePipeRemoteInformation:
|
|
|
|
if (*LengthRemaining >= sizeof(FILE_PIPE_REMOTE_INFORMATION)) {
|
|
|
|
PFILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo = (PFILE_PIPE_REMOTE_INFORMATION)Buffer;
|
|
|
|
PipeRemoteInfo->CollectDataTime = Fobx->Specific.NamedPipe.CollectDataTime;
|
|
PipeRemoteInfo->MaximumCollectionCount = Fobx->Specific.NamedPipe.CollectDataSize;
|
|
|
|
//
|
|
// Update the buffer length
|
|
//
|
|
|
|
*LengthRemaining -= sizeof( FILE_PIPE_REMOTE_INFORMATION );
|
|
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("RxQueryPipeInfo: *LengthRemaining = %08lx\n", *LengthRemaining) );
|
|
return Status;
|
|
}
|
|
|
|
|
|
|