windows-nt/Source/XPSP1/NT/base/fs/dfs/driver/fsctrl.c

1843 lines
48 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//-----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: fsctrl.c
//
// Contents:
// This module implements the File System Control routines for Dsfs called
// by the dispatch driver.
//
// Functions:
// DfsFsdFileSystemControl
// DfsFspFileSystemControl
// DfsCommonFileSystemControl, local
// DfsUserFsctl, local
// DfsInsertProvider - Helper routine for DfsFsctrlDefineProvider
// DfsFsctrlReadCtrs - Read the Dfs driver perfmon counters
// DfsFsctrlGetServerName - Get name of server given prefix
// DfsFsctrlReadStruct - return an internal data struct (debug build only)
// DfsFsctrlReadMem - return internal memory (debug build only)
// DfsCompleteMountRequest - Completion routine for mount IRP
// DfsCompleteLoadFsRequest - Completion routine for Load FS IRP
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include "attach.h"
#include "registry.h"
#include "regkeys.h"
#include "know.h"
#include "localvol.h"
#include "lvolinit.h"
#include "fsctrl.h"
#include "sitesup.h"
#include "ipsup.h"
#include "spcsup.h"
#include "dfslpc.h"
#include "dfswml.h"
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_FSCTRL)
//
// Local procedure prototypes
//
NTSTATUS
DfsCommonFileSystemControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DfsUserFsctl (
IN PIRP Irp
);
NTSTATUS
DfsFsctrlStartDfs(
IN PIRP Irp);
VOID DfsSetMachineState();
NTSTATUS
DfsFsctrlGetServerName(
IN PIRP Irp,
IN PUCHAR InputBuffer,
IN ULONG InputBufferLength,
IN PUCHAR OutputBuffer,
IN ULONG OutputBufferLength);
#if DBG
NTSTATUS
DfsFsctrlReadStruct (
IN PIRP Irp,
IN PFILE_DFS_READ_STRUCT_PARAM pRsParam,
IN ULONG InputBufferLength,
IN OUT PUCHAR OutputBuffer,
IN ULONG OutputBufferLength
);
NTSTATUS
DfsFsctrlReadMem (
IN PIRP Irp,
IN PFILE_DFS_READ_MEM Request,
IN ULONG InputBufferLength,
IN OUT PUCHAR OutputBuffer,
IN ULONG OutputBufferLength
);
#endif
NTSTATUS
DfsCompleteMountRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
DfsCompleteLoadFsRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
DfsFsctrlGetPkt(
IN PIRP Irp,
IN PUCHAR OutputBuffer,
IN ULONG OutputBufferLength);
NTSTATUS
DfsGetPktSize(
OUT PULONG pSize);
NTSTATUS
DfsGetPktMarshall(
IN PBYTE Buffer,
IN ULONG Size);
#if DBG
VOID
DfsGetDebugFlags(void);
#endif
VOID
DfsGetEventLogValue(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsFsdFileSystemControl )
#pragma alloc_text( PAGE, DfsCommonFileSystemControl )
#pragma alloc_text( PAGE, DfsUserFsctl )
#pragma alloc_text( PAGE, DfsSetMachineState)
#pragma alloc_text( PAGE, DfsInsertProvider )
#pragma alloc_text( PAGE, DfsFsctrlGetServerName )
#pragma alloc_text( PAGE, DfspStringInBuffer)
#pragma alloc_text( PAGE, DfsFsctrlGetPkt)
#pragma alloc_text( PAGE, DfsGetPktSize)
#pragma alloc_text( PAGE, DfsGetPktMarshall)
#if DBG
#pragma alloc_text( PAGE, DfsFsctrlReadStruct )
#pragma alloc_text( PAGE, DfsFsctrlReadMem )
#endif // DBG
//
// The following routines cannot be paged because they are completion
// routines which can be called at raised IRQL
//
// DfsCompleteMountRequest
// DfsCompleteLoadFsRequest
//
#endif // ALLOC_PRAGMA
//+-------------------------------------------------------------------
//
// Function: DfsFsdFileSystemControl, public
//
// Synopsis: This routine implements the FSD part of FileSystem
// control operations
//
// Arguments: [DeviceObject] -- Supplies the volume device object
// where the file exists
// [Irp] -- Supplies the Irp being processed
//
// Returns: [NTSTATUS] -- The FSD status for the IRP
//
//--------------------------------------------------------------------
NTSTATUS
DfsFsdFileSystemControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
) {
BOOLEAN Wait;
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PFILE_OBJECT FileObject = IrpSp->FileObject;
DebugTrace(+1, Dbg, "DfsFsdFileSystemControl\n", 0);
DFS_TRACE_HIGH(TRACE_IRP, DfsFsdFileSystemControl_Entry,
LOGPTR(FileObject)
LOGPTR(Irp));
//
// Call the common FileSystem Control routine, with blocking allowed
// if synchronous. This opeation needs to special case the mount
// and verify suboperations because we know they are allowed to block.
// We identify these suboperations by looking at the file object field
// and seeing if it's null.
//
if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
Wait = TRUE;
} else {
Wait = CanFsdWait( Irp );
}
FsRtlEnterFileSystem();
try {
Status = DfsCommonFileSystemControl( DeviceObject, Irp );
} except( DfsExceptionFilter( GetExceptionCode(), GetExceptionInformation() )) {
//
// We had some trouble trying to perform the requested
// operation, so we'll abort the I/O request with
// the error status that we get back from the
// execption code
//
Status = DfsProcessException( Irp, GetExceptionCode() );
}
FsRtlExitFileSystem();
//
// And return to our caller
//
DebugTrace(-1, Dbg, "DfsFsdFileSystemControl -> %08lx\n", ULongToPtr( Status ));
DFS_TRACE_HIGH(TRACE_IRP, DfsFsdFileSystemControl_Exit,
LOGSTATUS(Status)
LOGPTR(FileObject)
LOGPTR(Irp));
return Status;
}
//+-------------------------------------------------------------------
//
// Function: DfsCommonFileSystemControl, local
//
// Synopsis: This is the common routine for doing FileSystem control
// operations called by both the FSD and FSP threads
//
// Arguments: [DeviceObject] -- The one used to enter our FSD Routine
// [Irp] -- Supplies the Irp to process
//
// Returns: NTSTATUS - The return status for the operation
//--------------------------------------------------------------------
NTSTATUS
DfsCommonFileSystemControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
) {
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp, NextIrpSp;
PFILE_OBJECT FileObject;
ULONG FsControlCode;
//
// Get a pointer to the current Irp stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
FileObject = IrpSp->FileObject;
DFS_TRACE_LOW(TRACE_IRP, DfsCommonFileSystemControl_Entry,
LOGPTR(FileObject)
LOGPTR(Irp));
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
DebugTrace(+1, Dbg, "DfsCommonFileSystemControl\n", 0);
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);
//
// We know this is a file system control so we'll case on the
// minor function, and call a internal worker routine to complete
// the irp.
//
switch (IrpSp->MinorFunction) {
case IRP_MN_USER_FS_REQUEST:
//
// If the FSCTL is issued via a device that is not
// the DFS file system device object, then reject the request.
//
if (IS_DFS_CTL_CODE( FsControlCode )) {
if (DeviceObject == DfsData.FileSysDeviceObject) {
Status = DfsUserFsctl( Irp );
}
else {
DebugTrace(0, Dbg,"Dfs Fsctrl from invalid device object!\n", 0);
Status = STATUS_INVALID_DEVICE_REQUEST;
DFS_TRACE_HIGH(ERROR, DfsCommonFileSystemControl_Error_FsctrlFromInvalidDeviceObj,
LOGPTR(Irp)
LOGPTR(FileObject)
LOGSTATUS(Status));
DfsCompleteRequest( Irp, Status );
}
} else if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME ||
DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
Status = DfsVolumePassThrough(DeviceObject, Irp);
DebugTrace(0, Dbg, "Pass through user fsctrl -> %08lx\n", ULongToPtr( Status ) );
} else {
DebugTrace(0, Dbg, "Non Dfs Fsctrl code to Dfs File System Object!\n", 0);
Status = STATUS_INVALID_DEVICE_REQUEST;
DfsCompleteRequest( Irp, Status );
}
break;
case IRP_MN_MOUNT_VOLUME:
case IRP_MN_VERIFY_VOLUME:
ASSERT( DeviceObject != NULL );
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
Status = DfsVolumePassThrough(DeviceObject, Irp);
DebugTrace(0, Dbg, "Pass through user fsctrl -> %08lx\n", ULongToPtr( Status ) );
} else if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
//
// We are processing a MOUNT/VERIFY request being directed to
// another File System to which we have attached our own
// Attach File System Object. We setup a completion routine
// and forward the request.
//
NextIrpSp = IoGetNextIrpStackLocation(Irp);
(*NextIrpSp) = (*IrpSp);
IoSetCompletionRoutine(
Irp,
DfsCompleteMountRequest,
NULL,
TRUE,
TRUE,
TRUE);
//
// We want to pass the real device to the underlying file system
// so it can do its mount. See the comment in
// DfsCompleteMountRequest.
//
IrpSp->Parameters.MountVolume.DeviceObject =
IrpSp->Parameters.MountVolume.Vpb->RealDevice;
//
// Call the underlying file system via its file system device
//
Status = IoCallDriver(
((PDFS_ATTACH_FILE_SYSTEM_OBJECT)
DeviceObject)->TargetDevice,
Irp );
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonFileSystemControl_Error_Vol_IoCallDriver,
LOGSTATUS(Status)
LOGPTR(FileObject)
LOGPTR(Irp));
} else {
//
// We are processing a MOUNT/VERIFY request being directed to our
// our File System Device Object. We don't directly support
// disk volumes, so we simply reject.
//
ASSERT(DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM);
Status = STATUS_NOT_SUPPORTED;
DfsCompleteRequest( Irp, Status );
}
break;
case IRP_MN_LOAD_FILE_SYSTEM:
//
// This is a "load file system" fsctrl being sent to a file system
// recognizer to which we are attached. We first detach from the
// recognizer (so it can delete itself), then setup a completion
// routine and forward the request.
//
ASSERT( DeviceObject != NULL );
IoDetachDevice(
((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice);
NextIrpSp = IoGetNextIrpStackLocation(Irp);
(*NextIrpSp) = (*IrpSp);
IoSetCompletionRoutine(
Irp,
DfsCompleteLoadFsRequest,
NULL,
TRUE,
TRUE,
TRUE);
Status = IoCallDriver(
((PDFS_ATTACH_FILE_SYSTEM_OBJECT)
DeviceObject)->TargetDevice,
Irp );
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonFileSystemControl_Error_FS_IoCallDriver,
LOGSTATUS(Status)
LOGPTR(FileObject)
LOGPTR(Irp));
break;
default:
//
// Pass through all the rest we dont care about.
//
DebugTrace(0, Dbg, "Unknown FS Control Minor Function %08lx\n",
IrpSp->MinorFunction);
Status = DfsVolumePassThrough(DeviceObject, Irp);
break;
}
DebugTrace(-1, Dbg, "DfsCommonFileSystemControl -> %08lx\n", ULongToPtr( Status ));
DFS_TRACE_LOW(TRACE_IRP, DfsCommonFileSystemControl_Exit,
LOGSTATUS(Status)
LOGPTR(FileObject)
LOGPTR(Irp));
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsCompleteMountRequest, local
//
// Synopsis: Completion routine for a MOUNT fsctrl that was passed through
// to the underlying File System Device Object.
//
// This routine will simply see if the MOUNT succeeded. If it
// did, this routine will call DfsReattachToMountedVolume so
// any local volumes which were disabled by the unmount will be
// enabled again.
//
// Arguments: [DeviceObject] -- Our Attached File System Object.
// [Irp] -- The MOUNT fsctrl IRP.
// [Context] -- Unused
//
// Returns: [STATUS_SUCCESS] -- Always.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsCompleteMountRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
PDEVICE_OBJECT targetDevice;
PVPB vpb;
//
// Determine whether or not the request was successful and act accordingly.
//
DebugTrace(+1, Dbg,
"DfsCompleteMountRequest: Entered %08lx\n", ULongToPtr( Irp->IoStatus.Status ));
if (NT_SUCCESS( Irp->IoStatus.Status )) {
//
// Note that the VPB must be picked up from the target device object
// in case the file system did a remount of a previous volume, in
// which case it has replaced the VPB passed in as the target with
// a previously mounted VPB. Note also that in the mount dispatch
// routine, this driver *replaced* the DeviceObject pointer with a
// pointer to the real device, not the device that the file system
// was supposed to talk to, since this driver does not care.
//
vpb = irpSp->Parameters.MountVolume.DeviceObject->Vpb;
targetDevice = IoGetAttachedDevice( vpb->DeviceObject );
DebugTrace(0, Dbg, "Target Device %08lx\n", targetDevice);
DfsReattachToMountedVolume( targetDevice, vpb );
}
//
// If pending was returned, then propogate it to the caller.
//
if (Irp->PendingReturned) {
IoMarkIrpPending( Irp );
}
DebugTrace(-1, Dbg, "DfsCompleteMountRequest: Exited\n", 0);
return( STATUS_SUCCESS );
}
//+----------------------------------------------------------------------------
//
// Function: DfsCompleteLoadFsRequest, local
//
// Synopsis: Completion routine for a LOAD_FILE_SYSTEM fsctrl Irp. If
// the load did not succeed, this routine simply reattaches our
// Attached File System Object to the recognizer. If the load
// succeeds, this routine arranges to delete the Attached File
// System Object that was originally attached to the recognizer.
//
// Arguments: [DeviceObject] -- Attached File System Object.
// [Irp] -- The LOAD_FILE_SYSTEM Fsctrl Irp.
// [Context] -- Unused.
//
// Returns: [STATUS_SUCCESS] -- Always.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsCompleteLoadFsRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
if (NT_SUCCESS(Irp->IoStatus.Status)) {
RemoveEntryList(
&((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->FsoLinks);
//
// Due to refcounting done by the IO Subsystem, there's no way to
// delete the DeviceObject.
//
} else {
IoAttachDeviceByPointer(
DeviceObject,
((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice);
}
//
// If pending was returned, then propogate it to the caller
//
if (Irp->PendingReturned) {
IoMarkIrpPending( Irp );
}
return( STATUS_SUCCESS );
}
//+-------------------------------------------------------------------
//
// Function: DfsUserFsctl, local
//
// Synopsis: This is the common routine for implementing the user's
// requests made through NtFsControlFile.
//
// Arguments: [Irp] -- Supplies the Irp being processed
//
// Returns: NTSTATUS - The return status for the operation
//
//--------------------------------------------------------------------
NTSTATUS
DfsUserFsctl (
IN PIRP Irp
) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PIO_STACK_LOCATION NextIrpSp;
NTSTATUS Status;
ULONG FsControlCode;
ULONG cbOutput;
ULONG cbInput;
PUCHAR InputBuffer;
PUCHAR OutputBuffer;
//
// Just in case some-one (cough) forgets about it...
// ...zero information status now!
//
Irp->IoStatus.Information = 0L;
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
cbInput = IrpSp->Parameters.FileSystemControl.InputBufferLength;
cbOutput = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
DebugTrace(+1, Dbg, "DfsUserFsctl: Entered\n", 0);
DebugTrace( 0, Dbg, "DfsUserFsctl: Cntrl Code -> %08lx\n", ULongToPtr( FsControlCode ));
DebugTrace( 0, Dbg, "DfsUserFsctl: cbInput -> %08lx\n", ULongToPtr( cbInput ));
DebugTrace( 0, Dbg, "DfsUserFsctl: cbOutput -> %08lx\n", ULongToPtr( cbOutput ));
//
// All DFS FsControlCodes use METHOD_BUFFERED, so the SystemBuffer
// is used for both the input and output.
//
InputBuffer = OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
DebugTrace( 0, Dbg, "DfsUserFsctl: InputBuffer -> %08lx\n", InputBuffer);
DebugTrace( 0, Dbg, "DfsUserFsctl: UserBuffer -> %08lx\n", Irp->UserBuffer);
//
// Case on the control code.
//
switch ( FsControlCode ) {
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
case FSCTL_REQUEST_BATCH_OPLOCK:
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
case FSCTL_OPLOCK_BREAK_NOTIFY:
case FSCTL_DFS_READ_METERS:
case FSCTL_SRV_DFSSRV_IPADDR:
Status = STATUS_INVALID_DEVICE_REQUEST;
DfsCompleteRequest( Irp, Status );
break;
case FSCTL_DISMOUNT_VOLUME:
Status = STATUS_NOT_SUPPORTED;
DfsCompleteRequest( Irp, Status );
break;
case FSCTL_DFS_GET_VERSION:
if (OutputBuffer != NULL &&
cbOutput >= sizeof(DFS_GET_VERSION_ARG)) {
PDFS_GET_VERSION_ARG parg =
(PDFS_GET_VERSION_ARG) OutputBuffer;
parg->Version = 1;
Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(DFS_GET_VERSION_ARG);
} else {
Status = STATUS_INVALID_PARAMETER;
}
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_IS_ROOT:
if (DfsData.MachineState == DFS_UNKNOWN) {
DfsSetMachineState();
}
if (DfsData.MachineState == DFS_ROOT_SERVER) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INVALID_DOMAIN_ROLE;
}
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_ISDC:
DfsData.IsDC = TRUE;
Status = STATUS_SUCCESS;
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_ISNOTDC:
DfsData.IsDC = FALSE;
Status = STATUS_SUCCESS;
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_GET_ENTRY_TYPE:
Status = DfsFsctrlGetEntryType(
Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput);
break;
case FSCTL_DFS_MODIFY_PREFIX:
Status = DfsFsctrlModifyLocalVolPrefix(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_CREATE_EXIT_POINT:
Status = DfsFsctrlCreateExitPoint(
Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput
);
break;
case FSCTL_DFS_DELETE_EXIT_POINT:
Status = DfsFsctrlDeleteExitPoint(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_START_DFS:
DfsGetEventLogValue();
#if DBG
DfsGetDebugFlags();
#endif // DBG
Status = DfsFsctrlStartDfs(
Irp);
if (DfsData.MachineState == DFS_UNKNOWN) {
DfsSetMachineState();
}
//
// Try to validate our local partitions with a DC
//
break;
case FSCTL_DFS_STOP_DFS:
DfsGetEventLogValue();
#if DBG
DfsGetDebugFlags();
#endif // DBG
Status = DfsFsctrlStopDfs(
Irp
);
break;
case FSCTL_DFS_RESET_PKT:
Status = DfsFsctrlResetPkt(
Irp
);
break;
case FSCTL_DFS_MARK_STALE_PKT_ENTRIES:
Status = DfsFsctrlMarkStalePktEntries(
Irp
);
break;
case FSCTL_DFS_FLUSH_STALE_PKT_ENTRIES:
Status = DfsFsctrlFlushStalePktEntries(
Irp
);
break;
case FSCTL_DFS_INIT_LOCAL_PARTITIONS:
DfsInitLocalPartitions();
Status = STATUS_SUCCESS;
DfsCompleteRequest( Irp, Status);
break;
case FSCTL_DFS_CREATE_LOCAL_PARTITION:
Status = DfsFsctrlCreateLocalPartition(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_CREATE_SITE_INFO:
Status = DfsFsctrlCreateSiteInfo(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_DELETE_SITE_INFO:
Status = DfsFsctrlDeleteSiteInfo(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_CREATE_IP_INFO:
Status = DfsFsctrlCreateIpInfo(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_DELETE_IP_INFO:
Status = DfsFsctrlDeleteIpInfo(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_CREATE_SPECIAL_INFO:
Status = DfsFsctrlCreateSpcInfo(
DfsData.SpcHashTable,
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_DELETE_SPECIAL_INFO:
Status = DfsFsctrlDeleteSpcInfo(
DfsData.SpcHashTable,
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_CREATE_FTDFS_INFO:
Status = DfsFsctrlCreateSpcInfo(
DfsData.FtDfsHashTable,
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_DELETE_FTDFS_INFO:
Status = DfsFsctrlDeleteSpcInfo(
DfsData.FtDfsHashTable,
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_DELETE_LOCAL_PARTITION:
Status = DfsFsctrlDeleteLocalPartition(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_SET_LOCAL_VOLUME_STATE:
Status = DfsFsctrlSetVolumeState(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_SET_SERVICE_STATE:
Status = DfsFsctrlSetServiceState(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_DC_SET_VOLUME_STATE:
Status = DfsFsctrlDCSetVolumeState(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_SET_VOLUME_TIMEOUT:
Status = DfsFsctrlSetVolumeTimeout(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_IS_CHILDNAME_LEGAL:
Status = PktFsctrlIsChildnameLegal(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_PKT_CREATE_ENTRY:
Status = PktFsctrlCreateEntry(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_PKT_CREATE_SUBORDINATE_ENTRY:
Status = PktFsctrlCreateSubordinateEntry(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_PKT_DESTROY_ENTRY:
Status = PktFsctrlDestroyEntry(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_PKT_SET_RELATION_INFO:
Status = PktFsctrlSetRelationInfo(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_PKT_GET_RELATION_INFO:
Status = PktFsctrlGetRelationInfo(
Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput
);
break;
case FSCTL_DFS_GET_SERVER_INFO:
Status = DfsFsctrlGetServerInfo(
Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput);
break;
case FSCTL_DFS_SET_SERVER_INFO:
Status = PktFsctrlSetServerInfo(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_CHECK_STGID_IN_USE:
Status = DfsFsctrlCheckStgIdInUse(
Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput);
break;
case FSCTL_DFS_VERIFY_LOCAL_VOLUME_KNOWLEDGE:
Status = PktFsctrlVerifyLocalVolumeKnowledge(
Irp,
InputBuffer,
cbInput
);
break;
case FSCTL_DFS_PRUNE_LOCAL_PARTITION:
Status = PktFsctrlPruneLocalVolume(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_FIX_LOCAL_VOLUME:
Status = DfsFsctrlFixLocalVolumeKnowledge(Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_GET_SERVER_NAME:
Status = DfsFsctrlGetServerName(Irp,
InputBuffer,
cbInput,
OutputBuffer,
cbOutput);
break;
case FSCTL_SRV_DFSSRV_CONNECT:
Status = PktFsctrlDfsSrvConnect(Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_GET_PKT:
Status = DfsFsctrlGetPkt(Irp,
OutputBuffer,
cbOutput);
break;
case FSCTL_DFS_GET_NEXT_LONG_DOMAIN_NAME:
Status = DfsFsctrlGetDomainToRefresh(Irp,
OutputBuffer,
cbOutput);
break;
case FSCTL_DFS_REREAD_REGISTRY:
DfsGetEventLogValue();
#if DBG
DfsGetDebugFlags();
DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
#endif // DBG
DfspGetMaxReferrals();
Status = STATUS_SUCCESS;
DfsCompleteRequest(Irp, Status);
break;
#if DBG
case FSCTL_DFS_PKT_FLUSH_CACHE:
Status = PktFsctrlFlushCache(Irp, InputBuffer, cbInput);
break;
case FSCTL_DFS_DBG_BREAK:
DbgBreakPoint();
Status = STATUS_SUCCESS;
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_DBG_FLAGS:
DfsDebugTraceLevel = * ((PULONG) InputBuffer);
Status = STATUS_SUCCESS;
DfsCompleteRequest(Irp, Status);
break;
case FSCTL_DFS_SHUFFLE_ENTRY:
Status = PktFsctrlShufflePktEntry(
Irp,
InputBuffer,
cbInput);
break;
case FSCTL_DFS_INTERNAL_READ_MEM:
Status = DfsFsctrlReadMem(
Irp,
(PFILE_DFS_READ_MEM)InputBuffer,
cbInput,
OutputBuffer,
cbOutput );
break;
case FSCTL_DFS_INTERNAL_READSTRUCT:
Status = DfsFsctrlReadStruct(
Irp,
(PFILE_DFS_READ_STRUCT_PARAM)InputBuffer,
cbInput,
OutputBuffer,
cbOutput );
break;
#endif // DBG
default:
//
// This is not a recognized DFS fsctrl.
//
Status = STATUS_INVALID_PARAMETER;
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
break;
}
DebugTrace(-1, Dbg, "DfsUserFsctl: Exit -> %08lx\n", ULongToPtr( Status ) );
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlStartDfs
//
// Synopsis: Sets the state of the Dfs driver so that it will start
// receiving open requests.
//
// Arguments: [Irp] --
//
// Returns: [STATUS_SUCCESS] -- Successfully set the state to started.
//
// [STATUS_UNSUCCESSFUL] -- An error occured trying to set the
// state of Dfs to started. This is most likely because
// of a failure to register with the MUP.
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsFsctrlStartDfs(
IN PIRP Irp)
{
NTSTATUS status;
UNICODE_STRING dfsRootDeviceName;
STD_FSCTRL_PROLOGUE("DfsFsctrlStartDfs", FALSE, FALSE);
RtlInitUnicodeString(&dfsRootDeviceName, DFS_DEVICE_ROOT);
DfsSetMachineState();
DfsData.OperationalState = DFS_STATE_STARTED;
status = STATUS_SUCCESS;
DebugTrace(-1, Dbg, "DfsFsctrlStartDfs - returning %08lx\n", ULongToPtr( status ));
DfsCompleteRequest(Irp, status);
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsSetMachineState
//
// Synopsis: Gets the machine state from the registry and sets it in
// DfsData structure.
//
// Arguments: None
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsSetMachineState()
{
NTSTATUS Status;
DebugTrace(+1, Dbg, "DfsSetMachineState - Entered\n", 0);
Status = KRegSetRoot( wszRegRootVolumes );
if (NT_SUCCESS(Status)) {
DebugTrace(0, Dbg, "Found volumes dir %ws\n", wszRegRootVolumes );
DfsData.MachineState = DFS_ROOT_SERVER;
KRegCloseRoot();
} else if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
Status == STATUS_OBJECT_NAME_NOT_FOUND) {
//
// We default to DFS_CLIENT. When we later try to initialize local
// volumes, if we do have any, we'll upgrade ourselves to
// DFS_SERVER
//
DfsData.MachineState = DFS_CLIENT;
Status = STATUS_SUCCESS;
} else {
DebugTrace(0, Dbg, "Error %08lx opening volumes dir!\n", ULongToPtr( Status ) );
DfsData.MachineState = DFS_UNKNOWN;
}
DebugTrace(-1, Dbg, "DfsSetMachineState - Exited!\n", 0);
}
//+----------------------------------------------------------------------------
//
// Function: DfsInsertProvider
//
// Synopsis: Given a provider name, id, and capability, will add a new or
// overwrite an existing provider definition.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsInsertProvider(
IN PUNICODE_STRING ProviderName,
IN ULONG fProvCapability,
IN ULONG eProviderId)
{
PPROVIDER_DEF pProv = DfsData.pProvider;
int iProv;
//
// Find a free provider structure, or overwrite an existing one.
//
for (iProv = 0; iProv < DfsData.cProvider; iProv++, pProv++) {
if (pProv->eProviderId == eProviderId)
break;
}
if (iProv >= DfsData.maxProvider) {
ASSERT(iProv >= DfsData.maxProvider && "Out of provider structs");
return(STATUS_INSUFFICIENT_RESOURCES);
}
if (iProv < DfsData.cProvider) {
//
// Decrement reference counts on saved objects
//
if (pProv->FileObject)
ObDereferenceObject(pProv->FileObject);
if (pProv->DeviceObject)
ObDereferenceObject(pProv->DeviceObject);
if (pProv->DeviceName.Buffer)
ExFreePool(pProv->DeviceName.Buffer);
}
pProv->FileObject = NULL;
pProv->DeviceObject = NULL;
pProv->eProviderId = (USHORT) eProviderId;
pProv->fProvCapability = (USHORT) fProvCapability;
pProv->DeviceName = *ProviderName;
if (iProv == DfsData.cProvider) {
DfsData.cProvider++;
}
return(STATUS_SUCCESS);
}
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlGetServerName
//
// Synopsis: Given a Prefix in Dfs namespace it gets a server name for
// it.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsFsctrlGetServerName(
IN PIRP Irp,
IN PUCHAR InputBuffer,
IN ULONG InputBufferLength,
IN PUCHAR OutputBuffer,
IN ULONG OutputBufferLength)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT pkt;
PWCHAR pwchServer = (PWCHAR) OutputBuffer;
ULONG cChServer = 0;
ULONG MaxAllowed;
PDFS_PKT_ENTRY pEntry;
PWCHAR pwszPrefix = (PWCHAR) InputBuffer;
UNICODE_STRING ustrPrefix, RemainingPath;
PDFS_SERVICE pService;
PWCHAR pwch;
ULONG i;
STD_FSCTRL_PROLOGUE(DfsFsctrlGetServerName, TRUE, TRUE);
DebugTrace(+1,Dbg,"DfsFsctrlGetServerName()\n", 0);
//
// InputBuffer is a WCHAR. Check that the buffer is of even size, and
// has at least one character in it.
//
if (InputBufferLength < sizeof(WCHAR) || (InputBufferLength & 0x1) != 0) {
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
status = STATUS_INVALID_PARAMETER;
return status;
}
//
// Confirm there's a UNICODE NULL in there somewhere.
//
for (i = 0; i < InputBufferLength / sizeof(WCHAR); i++) {
if (pwszPrefix[i] == UNICODE_NULL) {
break;
}
}
if (i >= InputBufferLength / sizeof(WCHAR)) {
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
status = STATUS_INVALID_PARAMETER;
return status;
}
//
// Need to be able to put at least a UNICODE_NULL in the output buffer
//
if (OutputBufferLength >= sizeof(WCHAR)) {
MaxAllowed = OutputBufferLength/sizeof(WCHAR) - 1;
} else {
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
status = STATUS_INVALID_PARAMETER;
return status;
}
//
// Found a UNICODE_NULL in the buffer, so off we go...
//
RtlInitUnicodeString(&ustrPrefix, pwszPrefix);
pkt = _GetPkt();
PktAcquireExclusive(pkt, TRUE);
pEntry = PktLookupEntryByPrefix(pkt,
&ustrPrefix,
&RemainingPath);
if (pEntry == NULL) {
status = STATUS_OBJECT_NAME_NOT_FOUND;
} else {
//
// If there is a local service then return a NULL string.
//
if (pEntry->LocalService != NULL) {
*pwchServer = UNICODE_NULL;
cChServer = 1;
} else {
if (pEntry->ActiveService != NULL) {
pService = pEntry->ActiveService;
} else if (pEntry->Info.ServiceCount == 0) {
pService = NULL;
} else {
//
// Take first service.
//
pService = pEntry->Info.ServiceList;
}
if (pService != NULL) {
pwch = pService->Address.Buffer;
ASSERT(*pwch == L'\\');
pwch++;
while (*pwch != L'\\') {
*pwchServer++ = *pwch++;
if (++cChServer >= MaxAllowed) {
break;
}
}
*pwchServer = UNICODE_NULL;
DebugTrace(0, Dbg, "SERVERName Created %ws\n", pwchServer);
} else {
DebugTrace(0, Dbg, "No Service Exists for %ws\n", pwszPrefix);
status = DFS_STATUS_NO_SUCH_ENTRY;
}
}
}
PktRelease(pkt);
Irp->IoStatus.Information = cChServer * sizeof(WCHAR);
DfsCompleteRequest( Irp, status );
DebugTrace(-1,Dbg,"DfsFsctrlGetServerName: Exit->%08lx\n", ULongToPtr( status ));
return status;
}
//+----------------------------------------------------------------------------
//
// Function: DfspValidateString, private
//
// Synopsis: Check that a LPWSTR lies within a buffer.
//
// Arguments: [pwszString] -- pointer to string
//
// Returns: TRUE - string lies within buffer
// FALSE - bad alignment or string doesn't lie within buffer
//
//-----------------------------------------------------------------------------
BOOLEAN
DfspStringInBuffer(LPWSTR pwszString, PVOID Buffer, ULONG BufferLen)
{
PCHAR BufferEnd = (PCHAR)Buffer + BufferLen;
PWCHAR wcp;
//
// Buffer has to be large enough to at least contain a UNICODE_NULL
// The buffer has to be aligned correctly
// The start of the string has to lie within the buffer
//
if (BufferLen < sizeof(WCHAR) ||
!ALIGNMENT_IS_VALID(Buffer, PWCHAR) ||
!POINTER_IS_VALID(pwszString, Buffer, BufferLen)
) {
return FALSE;
}
//
// Scan the string and be sure we find a UNICODE_NULL within the buffer
//
for (wcp = pwszString; (PCHAR)wcp < BufferEnd; wcp++) {
if (*wcp == UNICODE_NULL) {
break;
}
}
if ((PCHAR)wcp >= BufferEnd) {
return FALSE;
}
//
// Looks good!!
//
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlGetPkt
//
// Synopsis: Returns the current (cached Pkt)
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsFsctrlGetPkt(
IN PIRP Irp,
IN PUCHAR OutputBuffer,
IN ULONG OutputBufferLength)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PDFS_PKT pkt;
BOOLEAN pktLocked = FALSE;
ULONG cbOutBuffer;
DebugTrace(+1, Dbg, "DfsFsctrlGetPkt\n", 0);
STD_FSCTRL_PROLOGUE("DfsFsctrlGetPkt", FALSE, TRUE);
pkt = _GetPkt();
PktAcquireShared( pkt, TRUE );
//
// Calculate the needed output buffer size
//
NtStatus = DfsGetPktSize(&cbOutBuffer);
//
// Let user know if it's too small
//
if (OutputBufferLength < cbOutBuffer) {
RETURN_BUFFER_SIZE(cbOutBuffer, NtStatus);
}
if (NT_SUCCESS(NtStatus)) {
//
// Args are ok, and it fits - marshall the data
//
NtStatus = DfsGetPktMarshall(OutputBuffer, cbOutBuffer);
Irp->IoStatus.Information = cbOutBuffer;
}
PktRelease(pkt);
DfsCompleteRequest( Irp, NtStatus );
DebugTrace(-1, Dbg, "DfsFsctrlGetPkt -> %08lx\n", ULongToPtr( NtStatus ) );
return( NtStatus );
}
//+----------------------------------------------------------------------------
//
// Function: DfsGetPktSize, private
//
// Synopsis: Calculates the size needed to return the Pkt. Helper for
// DfsFsctrlGetPkt().
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsGetPktSize(
PULONG pSize)
{
ULONG EntryCount = 0;
ULONG i;
ULONG Size = 0;
PDFS_PKT_ENTRY pPktEntry;
PDFS_PKT pkt = _GetPkt();
//
// Walk the linked list of Pkt entries
//
for ( pPktEntry = PktFirstEntry(pkt);
pPktEntry != NULL;
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
//
// Space for the Prefix and ShortPrefix, including a UNICODE_NULL
//
Size += pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
Size += pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
//
// Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
//
Size += sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
//
// Space for the ServerShare address, plus a UNICODE_NULL, plus the state
//
for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
Size += sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
}
EntryCount++;
}
//
// Space for the DFS_PKT_ARG, which will have EntryCount objects on the end
//
Size += FIELD_OFFSET(DFS_GET_PKT_ARG, EntryObject[EntryCount]);
//
// Make sure the size is a multiple of the size of a PDFS_PKT_ADDRESS_OBJECT, as that is what
// will be at the end of the buffer
//
while ((Size & (sizeof(PDFS_PKT_ADDRESS_OBJECT)-1)) != 0) {
Size++;
}
*pSize = Size;
return STATUS_SUCCESS;
}
//+----------------------------------------------------------------------------
//
// Function: DfsGetPktMarshall, private
//
// Synopsis: Marshalls the Pkt. Helper for DfsFsctrlGetPkt().
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsGetPktMarshall(
PBYTE Buffer,
ULONG Size)
{
ULONG EntryCount = 0;
ULONG i;
ULONG j;
ULONG Type;
PCHAR pCh;
PDFS_PKT_ENTRY pPktEntry;
PDFS_GET_PKT_ARG pPktArg;
PDFS_PKT pkt = _GetPkt();
//
// This will be a two-pass operation, the first pass will calculate how
// much room for the LPWSTR arrays at the end of the buffer, then the
// second pass will put the strings into place, too.
//
RtlZeroMemory(Buffer,Size);
//
// Point to the end of the buffer
//
pCh = (PCHAR)(Buffer + Size);
pPktArg = (PDFS_GET_PKT_ARG)Buffer;
for ( pPktEntry = PktFirstEntry(pkt);
pPktEntry != NULL;
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
//
// Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
//
pCh -= sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
pPktArg->EntryObject[EntryCount].Address = (PDFS_PKT_ADDRESS_OBJECT *)pCh;
EntryCount++;
}
//
// Now marshall
//
EntryCount = 0;
for ( pPktEntry = PktFirstEntry(pkt);
pPktEntry != NULL;
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
pCh -= pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
pPktArg->EntryObject[EntryCount].Prefix = (LPWSTR)pCh;
RtlCopyMemory(
pPktArg->EntryObject[EntryCount].Prefix,
pPktEntry->Id.Prefix.Buffer,
pPktEntry->Id.Prefix.Length);
pCh -= pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
pPktArg->EntryObject[EntryCount].ShortPrefix = (LPWSTR)pCh;
RtlCopyMemory(
pPktArg->EntryObject[EntryCount].ShortPrefix,
pPktEntry->Id.ShortPrefix.Buffer,
pPktEntry->Id.ShortPrefix.Length);
pPktArg->EntryObject[EntryCount].Type = pPktEntry->Type;
pPktArg->EntryObject[EntryCount].USN = pPktEntry->USN;
pPktArg->EntryObject[EntryCount].ExpireTime = pPktEntry->ExpireTime;
pPktArg->EntryObject[EntryCount].UseCount = pPktEntry->UseCount;
pPktArg->EntryObject[EntryCount].Uid = pPktEntry->Id.Uid;
pPktArg->EntryObject[EntryCount].ServiceCount = pPktEntry->Info.ServiceCount;
for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
Type = pPktEntry->Info.ServiceList[i].Type;
pCh -= sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
pPktArg->EntryObject[EntryCount].Address[i] = (PDFS_PKT_ADDRESS_OBJECT)pCh;
pPktArg->EntryObject[EntryCount].Address[i]->State = (USHORT)Type;
RtlCopyMemory(
&pPktArg->EntryObject[EntryCount].Address[i]->ServerShare[0],
pPktEntry->Info.ServiceList[i].Address.Buffer,
pPktEntry->Info.ServiceList[i].Address.Length);
}
EntryCount++;
}
pPktArg->EntryCount = EntryCount;
//
// Convert all the pointers to relative offsets
//
for (i = 0; i < pPktArg->EntryCount; i++) {
for (j = 0; j < pPktArg->EntryObject[i].ServiceCount; j++) {
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address[j], Buffer);
}
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Prefix, Buffer);
POINTER_TO_OFFSET(pPktArg->EntryObject[i].ShortPrefix, Buffer);
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address, Buffer);
}
return STATUS_SUCCESS;
}
#if DBG
//+-------------------------------------------------------------------------
//
// Function: DfsFsctrlReadMem, local
//
// Synopsis: DfsFsctrlReadMem is a debugging function which will return
// the contents of a chunk of kernel space memory
//
// Arguments: [IrpContext] -
// [Irp] -
// [Request] -- Pointer to a FILE_DFS_READ_MEM struct,
// giving the description of the data to be returned.
// [InputBufferLength] -- Size of InputBuffer
// [OutputBuffer] -- User's output buffer, in which the
// data structure will be returned.
// [OutputBufferLength] -- Size of OutputBuffer
//
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
//
// Notes: Available in DBG builds only.
//
//--------------------------------------------------------------------------
NTSTATUS
DfsFsctrlReadMem (
IN PIRP Irp,
IN PFILE_DFS_READ_MEM Request,
IN ULONG InputBufferLength,
IN OUT PUCHAR OutputBuffer,
IN ULONG OutputBufferLength
) {
NTSTATUS Status;
PUCHAR ReadBuffer;
ULONG ReadLength;
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//+-------------------------------------------------------------------------
//
// Function: DfsFsctrlReadStruct, local
//
// Synopsis: DfsFsctrlReadStruct is a debugging function which will return
// structures associated with the Dfs Server.
//
// Arguments: [Irp] -
// [InputBuffer] -- Pointer to a FILE_DFS_READ_STRUCT_PARAM,
// giving the description of the data structure to be
// returned.
// [InputBufferLength] -- Size of InputBuffer
// [OutputBuffer] -- User's output buffer, in which the
// data structure will be returned.
// [OutputBufferLength] -- Size of OutputBuffer
//
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
//
// Notes: Available in DBG builds only.
//
//--------------------------------------------------------------------------
NTSTATUS
DfsFsctrlReadStruct (
IN PIRP Irp,
IN PFILE_DFS_READ_STRUCT_PARAM pRsParam,
IN ULONG InputBufferLength,
IN OUT PUCHAR OutputBuffer,
IN ULONG OutputBufferLength
) {
NTSTATUS Status;
NODE_TYPE_CODE NodeTypeCode;
PUCHAR ReadBuffer;
ULONG ReadLength;
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
#endif