|
|
//-----------------------------------------------------------------------------
//
// 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
|