1843 lines
48 KiB
C
1843 lines
48 KiB
C
//-----------------------------------------------------------------------------
|
||
//
|
||
// 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
|