1160 lines
34 KiB
C
1160 lines
34 KiB
C
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Copyright (C) 1992, Microsoft Corporation.
|
|||
|
//
|
|||
|
// File: attach.c
|
|||
|
//
|
|||
|
// Contents: This module contains routines for managing attached file
|
|||
|
// systems.
|
|||
|
//
|
|||
|
// Functions:
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
#include "dfsprocs.h"
|
|||
|
#include "attach.h"
|
|||
|
#include "dfswml.h"
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_ATTACH)
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsReferenceVdoByFileName(
|
|||
|
IN PUNICODE_STRING TargetName,
|
|||
|
OUT PDEVICE_OBJECT *DeviceObject,
|
|||
|
OUT PDEVICE_OBJECT *RealDeviceObject,
|
|||
|
OUT PULONG DevObjNameLen OPTIONAL
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
DfsAttachToFileSystem(
|
|||
|
IN PDEVICE_OBJECT FileSystemObject);
|
|||
|
|
|||
|
VOID
|
|||
|
DfsDetachFromFileSystem(
|
|||
|
IN PDEVICE_OBJECT FileSystemObject);
|
|||
|
|
|||
|
PDEVICE_OBJECT
|
|||
|
DfsGetDfsFilterDeviceObject(
|
|||
|
IN PFILE_OBJECT targetFile);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGE, DfsReferenceVdoByFileName )
|
|||
|
#pragma alloc_text( PAGE, DfsGetAttachName )
|
|||
|
#pragma alloc_text( PAGE, DfsSetupVdo)
|
|||
|
#pragma alloc_text( PAGE, DfsAttachVolume )
|
|||
|
#pragma alloc_text( PAGE, DfsDetachVolume )
|
|||
|
#pragma alloc_text( PAGE, DfsGetDfsFilterDeviceObject)
|
|||
|
|
|||
|
//
|
|||
|
// The following are not pageable since they can be called at DPC level
|
|||
|
//
|
|||
|
// DfsVolumePassThrough
|
|||
|
//
|
|||
|
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
|
|||
|
//
|
|||
|
// Generator value for local provider IDs.
|
|||
|
//
|
|||
|
|
|||
|
static USHORT LocalProviderID = 0xF000;
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsReferenceVdoByFileName, private
|
|||
|
//
|
|||
|
// Synopsis: Given a file path name, this function will return a pointer
|
|||
|
// to its corresponding volume device object.
|
|||
|
//
|
|||
|
// Arguments: [TargetName] -- File path name of the root directory of the
|
|||
|
// local volume.
|
|||
|
// [DeviceObject] -- Upon successful return, contains a
|
|||
|
// referenced pointer to the first attached device
|
|||
|
// object for the file.
|
|||
|
// [RealDeviceObject] -- Upon successful return, contains a
|
|||
|
// non-referenced pointer to the real device object
|
|||
|
// for the file.
|
|||
|
// [DevObjNameLen] -- An optional argument, which if present,
|
|||
|
// gives the length (in bytes) of the path to the
|
|||
|
// returned device object.
|
|||
|
//
|
|||
|
// Returns: NTSTATUS -- STATUS_SUCCESS if successful. Otherwise, the
|
|||
|
// status returned by the file open attempt.
|
|||
|
//
|
|||
|
// Notes: This could return a pointer to a DFS volume object if one
|
|||
|
// has already been attached.
|
|||
|
//
|
|||
|
// ObDereferenceObject must be called on the returned
|
|||
|
// DeviceObject
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsReferenceVdoByFileName(
|
|||
|
IN PUNICODE_STRING TargetName,
|
|||
|
OUT PDEVICE_OBJECT *DeviceObject,
|
|||
|
OUT PDEVICE_OBJECT *RealDeviceObject,
|
|||
|
OUT PULONG DevObjNameLen OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING fileName;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
IO_STATUS_BLOCK ioStatusBlock;
|
|||
|
HANDLE targetFileHandle = NULL;
|
|||
|
OBJECT_HANDLE_INFORMATION handleInformation;
|
|||
|
PFILE_OBJECT targetFileObject;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsReferenceVdoByFileName: Entered\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// Make sure what we have is indeed a file name, and not a device name!
|
|||
|
//
|
|||
|
|
|||
|
if (TargetName->Buffer[ TargetName->Length/sizeof(WCHAR) - 1 ] ==
|
|||
|
UNICODE_DRIVE_SEP) {
|
|||
|
|
|||
|
fileName.Length = 0;
|
|||
|
fileName.MaximumLength = TargetName->Length + 2 * sizeof(WCHAR);
|
|||
|
fileName.Buffer = ExAllocatePoolWithTag(PagedPool, fileName.MaximumLength, ' sfD');
|
|||
|
|
|||
|
if (fileName.Buffer == NULL) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"Unable to allocate %d bytes\n", fileName.MaximumLength);
|
|||
|
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
RtlCopyUnicodeString(&fileName, TargetName);
|
|||
|
|
|||
|
RtlAppendUnicodeToString(
|
|||
|
&fileName,
|
|||
|
(LPWSTR) UNICODE_PATH_SEP_STR);
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
fileName = *TargetName;
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// create the object attribtues argument
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&objectAttributes,
|
|||
|
&fileName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
DebugTrace(0,Dbg, "DfsReferenceVdoByFileName: Attempting to open file [%wZ]\n", &fileName );
|
|||
|
|
|||
|
//
|
|||
|
// Open the root of the volume
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwOpenFile(&targetFileHandle,
|
|||
|
FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY,
|
|||
|
&objectAttributes,
|
|||
|
&ioStatusBlock,
|
|||
|
FILE_SHARE_READ,
|
|||
|
FILE_DIRECTORY_FILE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if we have successfully opened the file then we begin the
|
|||
|
// task of getting a reference to the file object itself.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
DebugTrace(0,Dbg,
|
|||
|
"DfsReferenceVdoByFileName: Attempting get file object \n", 0);
|
|||
|
|
|||
|
Status = ObReferenceObjectByHandle(
|
|||
|
targetFileHandle,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
KernelMode,
|
|||
|
(PVOID *)&targetFileObject,
|
|||
|
&handleInformation);
|
|||
|
|
|||
|
//
|
|||
|
// if we have successfully obtained a reference to the file object
|
|||
|
// we can now begin the task of getting the related device object.
|
|||
|
//
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
*DeviceObject = DfsGetDfsFilterDeviceObject(targetFileObject);
|
|||
|
|
|||
|
if (*DeviceObject == NULL) {
|
|||
|
*DeviceObject = IoGetRelatedDeviceObject(targetFileObject);
|
|||
|
}
|
|||
|
|
|||
|
*RealDeviceObject = targetFileObject->Vpb->RealDevice;
|
|||
|
|
|||
|
Status = ObReferenceObjectByPointer(
|
|||
|
*DeviceObject,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
KernelMode);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(DevObjNameLen)) {
|
|||
|
|
|||
|
ASSERT(
|
|||
|
fileName.Length > targetFileObject->FileName.Length);
|
|||
|
|
|||
|
*DevObjNameLen = fileName.Length -
|
|||
|
targetFileObject->FileName.Length;
|
|||
|
}
|
|||
|
|
|||
|
ObDereferenceObject(targetFileObject);
|
|||
|
|
|||
|
DebugTrace( 0, Dbg, "Referenced Vdo [%08lx]\n", *DeviceObject);
|
|||
|
|
|||
|
DebugTrace( 0, Dbg, "Real Device Object [%08lx]\n",
|
|||
|
*RealDeviceObject);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ZwClose(targetFileHandle);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (fileName.Buffer != NULL && fileName.Buffer != TargetName->Buffer) {
|
|||
|
|
|||
|
ExFreePool( fileName.Buffer );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1,Dbg, "DfsReferenceVdoByFileName: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsGetAttachName, public
|
|||
|
//
|
|||
|
// Synopsis: A DFS local volume storage ID is parsed into the portion
|
|||
|
// which refers to a volume device object, and the portion
|
|||
|
// which refers to the volume-relative path to the root of
|
|||
|
// the local volume storageID.
|
|||
|
//
|
|||
|
// Arguments: [LocalVolumeStorageId] -- file path name of the root of
|
|||
|
// the local DFS volume.
|
|||
|
// [LocalVolumeRelativeName] -- the name of LocalVolumeStorageId
|
|||
|
// relative to the volume object name. This
|
|||
|
// includes a leading \.
|
|||
|
//
|
|||
|
// Returns: Status from DfsReferenceVdoByFileName()
|
|||
|
//
|
|||
|
// Notes: The returned string is a pointer into the input string.
|
|||
|
// The string storage should be duplicated as needed.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsGetAttachName(
|
|||
|
IN PUNICODE_STRING LocalVolumeStorageId,
|
|||
|
OUT PUNICODE_STRING LocalVolumeRelativeName
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PDEVICE_OBJECT targetVdo, realDevice;
|
|||
|
ULONG volNameLen;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsGetAttachName: Entered\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// Get our hands on the volume object
|
|||
|
//
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"DfsGetAttachName: Attempting to reference volume\n", 0);
|
|||
|
|
|||
|
Status = DfsReferenceVdoByFileName(
|
|||
|
LocalVolumeStorageId,
|
|||
|
&targetVdo,
|
|||
|
&realDevice,
|
|||
|
&volNameLen);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
*LocalVolumeRelativeName = *LocalVolumeStorageId;
|
|||
|
|
|||
|
if (LocalVolumeRelativeName->Length -= (USHORT)volNameLen) {
|
|||
|
|
|||
|
LocalVolumeRelativeName->Buffer =
|
|||
|
(PWCHAR)((PCHAR)LocalVolumeRelativeName->Buffer + volNameLen);
|
|||
|
|
|||
|
ASSERT (LocalVolumeRelativeName->Buffer[0] == UNICODE_PATH_SEP);
|
|||
|
|
|||
|
LocalVolumeRelativeName->MaximumLength -=
|
|||
|
LocalVolumeStorageId->Length - LocalVolumeRelativeName->Length;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
LocalVolumeRelativeName->Buffer = NULL;
|
|||
|
|
|||
|
LocalVolumeRelativeName->MaximumLength = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ObDereferenceObject(targetVdo);
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1,Dbg, "DfsGetAttachName: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsAttachVolume, public
|
|||
|
//
|
|||
|
// Synopsis: A DFS volume device object is attached to the volume
|
|||
|
// device object for some local file system, and a provider
|
|||
|
// definition is built for the local volume.
|
|||
|
//
|
|||
|
// Arguments: [RootName] -- file path name of the root of the local
|
|||
|
// volume.
|
|||
|
// [ppProvider] -- On successful return, contains a pointer
|
|||
|
// to a PROVIDER_DEF record that descibes the
|
|||
|
// attached device.
|
|||
|
//
|
|||
|
// Returns: [STATUS_INSUFFICIENT_RESOURCES] -- If unable to allocate
|
|||
|
// pool for provider name.
|
|||
|
//
|
|||
|
// Status from DfsSetupVdo()
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsAttachVolume(
|
|||
|
IN PUNICODE_STRING RootName,
|
|||
|
OUT PPROVIDER_DEF *ppProvider
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PDEVICE_OBJECT targetVdo, realDevice;
|
|||
|
PDFS_VOLUME_OBJECT dfsVdo = NULL;
|
|||
|
ULONG volNameLen;
|
|||
|
BOOLEAN fReferenced = FALSE;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsAttachVolume: Entered\n", 0);
|
|||
|
|
|||
|
Status = DfsReferenceVdoByFileName(
|
|||
|
RootName,
|
|||
|
&targetVdo,
|
|||
|
&realDevice,
|
|||
|
&volNameLen);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
fReferenced = TRUE;
|
|||
|
|
|||
|
if (targetVdo->DeviceType != FILE_DEVICE_DFS_VOLUME) {
|
|||
|
Status = DfsSetupVdo(RootName, targetVdo, realDevice, volNameLen, &dfsVdo);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
InsertTailList(&DfsData.AVdoQueue, &dfsVdo->VdoLinks);
|
|||
|
dfsVdo->DfsEnable = TRUE;
|
|||
|
dfsVdo->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Upon dereferencing the volume device object, we found one
|
|||
|
// of our own Vdos. Just bump the reference count on it.
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"DfsAttachVolume: Attaching multiple times to device %x\n",
|
|||
|
targetVdo);
|
|||
|
|
|||
|
dfsVdo = (PDFS_VOLUME_OBJECT) targetVdo;
|
|||
|
dfsVdo->DfsEnable = TRUE;
|
|||
|
dfsVdo->AttachCount++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
*ppProvider = &dfsVdo->Provider;
|
|||
|
}
|
|||
|
|
|||
|
if (fReferenced) {
|
|||
|
ObDereferenceObject(targetVdo);
|
|||
|
}
|
|||
|
|
|||
|
DfspGetMaxReferrals();
|
|||
|
|
|||
|
DebugTrace(-1,Dbg, "DfsAttachVolume: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsDetachVolume, public
|
|||
|
//
|
|||
|
// Synopsis: The DFS volume device object referred to by the file
|
|||
|
// RootName is dereferenced. If it is the last reference,
|
|||
|
// the Vdo is detached from the device chain.
|
|||
|
//
|
|||
|
// Arguments: [RootName] -- file path name of the root of the local
|
|||
|
// volume.
|
|||
|
//
|
|||
|
// Returns: Status from DfsReferenceVdoByFileName
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsDetachVolume(
|
|||
|
IN PUNICODE_STRING RootName
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PDFS_VOLUME_OBJECT dfsVdo;
|
|||
|
PDEVICE_OBJECT realDevice;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsDetachVolume: Entered\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// Get our hands on the volume object
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "DfsDetachVolume: Attempting to reference volume\n", 0);
|
|||
|
|
|||
|
Status = DfsReferenceVdoByFileName(
|
|||
|
RootName,
|
|||
|
(PDEVICE_OBJECT *)&dfsVdo,
|
|||
|
&realDevice,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// We should have our hands on one of our device objects
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if ((dfsVdo->DeviceObject.DeviceType == FILE_DEVICE_DFS_VOLUME) &&
|
|||
|
(--dfsVdo->AttachCount == 0)) {
|
|||
|
|
|||
|
//
|
|||
|
// Go ahead and detach the device
|
|||
|
//
|
|||
|
|
|||
|
dfsVdo->DfsEnable = FALSE;
|
|||
|
}
|
|||
|
ObDereferenceObject(dfsVdo);
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1,Dbg, "DfsDetachVolume: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsDetachVolumeForDelete, public
|
|||
|
//
|
|||
|
// Synopsis: This routine does the work of detaching from a target
|
|||
|
// device object so that the target device object may be
|
|||
|
// deleted.
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments: [DfsVdo] -- The dfs attached device object.
|
|||
|
//
|
|||
|
// Returns:
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsDetachVolumeForDelete(
|
|||
|
IN PDEVICE_OBJECT DeviceObject)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the Pkt exclusively so no one will access this Vdo while we
|
|||
|
// are detaching it.
|
|||
|
//
|
|||
|
if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
|
|||
|
DfsDetachFromFileSystem( ((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice );
|
|||
|
} else {
|
|||
|
PDFS_PKT pkt;
|
|||
|
PDFS_VOLUME_OBJECT DfsVdo = (PDFS_VOLUME_OBJECT) DeviceObject;
|
|||
|
|
|||
|
pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireExclusive( pkt, TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// Detach from the underlying FS...
|
|||
|
//
|
|||
|
|
|||
|
IoDetachDevice(DfsVdo->Provider.DeviceObject);
|
|||
|
|
|||
|
//
|
|||
|
// Flag our provider to be unavailable...
|
|||
|
//
|
|||
|
|
|||
|
DfsVdo->Provider.fProvCapability |= PROV_UNAVAILABLE;
|
|||
|
|
|||
|
PktRelease( pkt );
|
|||
|
}
|
|||
|
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsReattachToMountedVolume, public
|
|||
|
//
|
|||
|
// Synopsis: If one runs chkdsk, format etc on a volume that has been
|
|||
|
// attached to, the underlying file system will need to
|
|||
|
// unmount the volume. This will be handled by the
|
|||
|
// DfsDetachVolumeForDelete routine above. Ater the operation is
|
|||
|
// done, the volume will need to be remounted again. This
|
|||
|
// routine will reattach on the remount.
|
|||
|
//
|
|||
|
// Arguments: [TargetDevice] -- The Volume Device Object for the volume
|
|||
|
// that was just mounted.
|
|||
|
//
|
|||
|
// [Vpb] -- The Volume Parameter Block of the volume that was
|
|||
|
// just mounted.
|
|||
|
//
|
|||
|
// Returns:
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsReattachToMountedVolume(
|
|||
|
IN PDEVICE_OBJECT TargetDevice,
|
|||
|
IN PVPB Vpb)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PDFS_PKT pkt;
|
|||
|
PUNICODE_PREFIX_TABLE_ENTRY lvPrefix;
|
|||
|
PDFS_LOCAL_VOL_ENTRY localVol;
|
|||
|
|
|||
|
//
|
|||
|
// If the local volumes are being initialized as we speak, we won't
|
|||
|
// check to see if there are any unmounted volumes that need to be
|
|||
|
// reattached. This is because we need to acquire the pkt to do the
|
|||
|
// check. However, the local volume init itself might be causing this
|
|||
|
// volume to be mounted, in which case they already have the Pkt locked.
|
|||
|
//
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|||
|
|
|||
|
if (DfsData.LvState == LV_INITINPROGRESS ||
|
|||
|
DfsData.LvState == LV_UNINITIALIZED) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Local volumes being initialized - no action taken\n", 0);
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
|
|||
|
//
|
|||
|
// We will go through all our local volumes to see if any of them have
|
|||
|
// a provider that has been detached (marked as PROV_UNAVAILABLE). If
|
|||
|
// we find any, we will see if the volume being mounted is one which
|
|||
|
// was dismounted before. If so, we reattach.
|
|||
|
//
|
|||
|
|
|||
|
pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireExclusive( pkt, TRUE );
|
|||
|
|
|||
|
lvPrefix = DfsNextUnicodePrefix(&pkt->LocalVolTable, TRUE);
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Looking for Real Device %08lx\n", Vpb->RealDevice);
|
|||
|
|
|||
|
while (lvPrefix != NULL) {
|
|||
|
|
|||
|
PPROVIDER_DEF provider;
|
|||
|
PDFS_VOLUME_OBJECT candidateObject;
|
|||
|
|
|||
|
localVol = (PDFS_LOCAL_VOL_ENTRY) CONTAINING_RECORD(
|
|||
|
lvPrefix,
|
|||
|
DFS_LOCAL_VOL_ENTRY,
|
|||
|
PrefixTableEntry);
|
|||
|
|
|||
|
ASSERT(localVol->PktEntry->LocalService != NULL);
|
|||
|
|
|||
|
provider = localVol->PktEntry->LocalService->pProvider;
|
|||
|
|
|||
|
if (provider != NULL) {
|
|||
|
|
|||
|
candidateObject = CONTAINING_RECORD(
|
|||
|
provider,
|
|||
|
DFS_VOLUME_OBJECT,
|
|||
|
Provider);
|
|||
|
|
|||
|
if (provider->fProvCapability & PROV_UNAVAILABLE) {
|
|||
|
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Examining dismounted volume [%wZ]\n",
|
|||
|
&localVol->PktEntry->Id.Prefix);
|
|||
|
|
|||
|
if (Vpb->RealDevice == candidateObject->RealDevice) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Found detached device %08lx\n",
|
|||
|
candidateObject);
|
|||
|
|
|||
|
provider->DeviceObject = TargetDevice;
|
|||
|
|
|||
|
Status = IoAttachDeviceByPointer(
|
|||
|
&candidateObject->DeviceObject,
|
|||
|
TargetDevice);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
provider->fProvCapability &= ~PROV_UNAVAILABLE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Real Device %08lx did not match\n",
|
|||
|
candidateObject->RealDevice);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
lvPrefix = DfsNextUnicodePrefix( &pkt->LocalVolTable, FALSE );
|
|||
|
|
|||
|
localVol = (PDFS_LOCAL_VOL_ENTRY) CONTAINING_RECORD(
|
|||
|
lvPrefix,
|
|||
|
DFS_LOCAL_VOL_ENTRY,
|
|||
|
PrefixTableEntry);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PktRelease( pkt );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsVolumePassThrough, public
|
|||
|
//
|
|||
|
// Synopsis: This is the main FSD routine that passes a request
|
|||
|
// on to an attached-to device, or to a redirected
|
|||
|
// file.
|
|||
|
//
|
|||
|
// Arguments: [DeviceObject] -- Supplies a pointer to the Dfs device
|
|||
|
// object this request was aimed at.
|
|||
|
// [Irp] -- Supplies a pointer to the I/O request packet.
|
|||
|
//
|
|||
|
// Returns: [STATUS_INVALID_DEVICE_REQUEST] -- If the DeviceObject
|
|||
|
// argument is of unknown type, or the type of file
|
|||
|
// is invalid for the request being performed.
|
|||
|
//
|
|||
|
// NT Status from calling the underlying file system that
|
|||
|
// opened the file.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsVolumePassThrough(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PIO_STACK_LOCATION NextIrpSp;
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsVolumePassThrough: Entered\n", 0);
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
FileObject = IrpSp->FileObject;
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "DeviceObject = %x\n", DeviceObject);
|
|||
|
DebugTrace(0, Dbg, "Irp = %x\n", Irp );
|
|||
|
DebugTrace(0, Dbg, " MajorFunction = %x\n", IrpSp->MajorFunction );
|
|||
|
DebugTrace(0, Dbg, " MinorFunction = %x\n", IrpSp->MinorFunction );
|
|||
|
|
|||
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|||
|
|
|||
|
PDEVICE_OBJECT Vdo;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the stack from one to the next...
|
|||
|
//
|
|||
|
|
|||
|
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
|
|||
|
(*NextIrpSp) = (*IrpSp);
|
|||
|
|
|||
|
IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Find out what device to call...and call it
|
|||
|
//
|
|||
|
|
|||
|
Vdo = ((PDFS_VOLUME_OBJECT) DeviceObject)->Provider.DeviceObject;
|
|||
|
|
|||
|
Status = IoCallDriver( Vdo, Irp );
|
|||
|
|
|||
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsVolumePassThrough_Error_Vol_IoCallDriver,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(Irp)
|
|||
|
LOGPTR(FileObject));
|
|||
|
|
|||
|
} else if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
|
|||
|
|
|||
|
PDEVICE_OBJECT Fso;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the stack from one to the next...
|
|||
|
//
|
|||
|
|
|||
|
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
|
|||
|
(*NextIrpSp) = (*IrpSp);
|
|||
|
|
|||
|
IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Find out what device to call...and call it
|
|||
|
//
|
|||
|
|
|||
|
Fso = ((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice;
|
|||
|
|
|||
|
Status = IoCallDriver( Fso, Irp );
|
|||
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsVolumePassThrough_Error_FS_IoCallDriver,
|
|||
|
LOGPTR(Irp)
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(FileObject));
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "DfsVolumePassThrough: Unexpected Dev = %x\n",
|
|||
|
DeviceObject);
|
|||
|
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
DFS_TRACE_HIGH(ERROR, DfsVolumePassThrough_Error1,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(FileObject)
|
|||
|
LOGPTR(Irp));
|
|||
|
|
|||
|
Irp->IoStatus.Status = Status;
|
|||
|
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsVolumePassThrough: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|||
|
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsFsNotification, public
|
|||
|
//
|
|||
|
// Synopsis: Routine to be registered as a callback with the IO subsystem.
|
|||
|
// It gets called every time a file system is loaded or
|
|||
|
// unloaded. Here, we attach to the file system so that we can
|
|||
|
// trap MOUNT fsctrls. We need to trap MOUNT fsctrls so that
|
|||
|
// we can attach to the Volume Device Objects of volumes that
|
|||
|
// are mounted in the Dfs namespace.
|
|||
|
//
|
|||
|
// Arguments: [FileSystemObject] -- The File System Device Object of the
|
|||
|
// File System that is being loaded/unloaded.
|
|||
|
//
|
|||
|
// [fLoading] -- TRUE if the File System is being loaded. FALSE
|
|||
|
// if it is being unloaded.
|
|||
|
//
|
|||
|
// Returns: Nothing.
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsFsNotification(
|
|||
|
IN PDEVICE_OBJECT FileSystemObject,
|
|||
|
IN BOOLEAN fLoading)
|
|||
|
{
|
|||
|
ASSERT( FileSystemObject->DriverObject != NULL );
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsFsNotification - Entered\n", 0);
|
|||
|
DebugTrace(0, Dbg, "File System [%wZ]\n", &FileSystemObject->DriverObject->DriverName);
|
|||
|
DebugTrace(0, Dbg, "%s\n", fLoading ? "Loading" : "Unloading" );
|
|||
|
|
|||
|
//
|
|||
|
// Check if this is a DISK based file system. If not, we don't care about
|
|||
|
// it.
|
|||
|
//
|
|||
|
|
|||
|
if (FileSystemObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM) {
|
|||
|
DebugTrace(-1, Dbg, "DfsFsNotification - Not Disk File System\n",0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// A disk file system is being loaded or unloaded. If it is being loaded,
|
|||
|
// we want to attach to the File System Device Object being passed in. If
|
|||
|
// it is being unloaded, we try to find our attached device and detach
|
|||
|
// ourselves.
|
|||
|
//
|
|||
|
|
|||
|
if (fLoading) {
|
|||
|
|
|||
|
DfsAttachToFileSystem( FileSystemObject );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DfsDetachFromFileSystem( FileSystemObject );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsNotification - Exited\n", 0);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsAttachToFileSystem
|
|||
|
//
|
|||
|
// Synopsis: Attaches to a File System Device Object so we can trap
|
|||
|
// MOUNT calls.
|
|||
|
//
|
|||
|
// Arguments: [FileSystemObject] -- The File System Object to attach to.
|
|||
|
//
|
|||
|
// Returns: Nothing
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsAttachToFileSystem(
|
|||
|
IN PDEVICE_OBJECT FileSystemObject)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PDFS_ATTACH_FILE_SYSTEM_OBJECT ourDevice;
|
|||
|
PDEVICE_OBJECT TargetFileSystemObject;
|
|||
|
|
|||
|
//
|
|||
|
// Create our own device object.
|
|||
|
//
|
|||
|
|
|||
|
Status = IoCreateDevice(
|
|||
|
DfsData.DriverObject, // Our own Driver Object
|
|||
|
sizeof(DFS_ATTACH_FILE_SYSTEM_OBJECT) -
|
|||
|
sizeof(DEVICE_OBJECT), // size of extension
|
|||
|
NULL, // Name - we don't need one
|
|||
|
FILE_DEVICE_DISK_FILE_SYSTEM, // Type of device
|
|||
|
0, // Device Characteristics
|
|||
|
FALSE, // Exclusive
|
|||
|
(PDEVICE_OBJECT *) &ourDevice); // On return, new device
|
|||
|
|
|||
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsAttachToFileSystem_Error_IoCreateDevice,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(FileSystemObject));
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Created File System Attach Device %08lx\n",
|
|||
|
ourDevice);
|
|||
|
|
|||
|
TargetFileSystemObject = IoAttachDeviceToDeviceStack(
|
|||
|
&ourDevice->DeviceObject,
|
|||
|
FileSystemObject );
|
|||
|
|
|||
|
if (TargetFileSystemObject != NULL) {
|
|||
|
|
|||
|
ourDevice->TargetDevice = TargetFileSystemObject;
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|||
|
|
|||
|
InsertTailList( &DfsData.AFsoQueue, &ourDevice->FsoLinks );
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
|
|||
|
|
|||
|
ourDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Unable to attach %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
IoDeleteDevice( (PDEVICE_OBJECT) ourDevice );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Unable to create Device Object %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsDetachFromFileSystem
|
|||
|
//
|
|||
|
// Synopsis: Finds and detaches a DFS_ATTACHED_FILE_SYSTEM_OBJECT from
|
|||
|
// its target File System Device Object.
|
|||
|
//
|
|||
|
// Arguments: [FileSystemObject] -- The one that purpotedly has one of our
|
|||
|
// device objects attached to it.
|
|||
|
//
|
|||
|
// Returns: Nothing
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsDetachFromFileSystem(
|
|||
|
IN PDEVICE_OBJECT FileSystemObject)
|
|||
|
{
|
|||
|
PDFS_ATTACH_FILE_SYSTEM_OBJECT attachedDevice, candidateDevice;
|
|||
|
PLIST_ENTRY nextAFsoLink;
|
|||
|
|
|||
|
//
|
|||
|
// First, we need to find our own device. For each device that is
|
|||
|
// attached to the FileSystemObject, we check our AFsoQueue to see if
|
|||
|
// the attached device belongs to us.
|
|||
|
//
|
|||
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|||
|
|
|||
|
for (attachedDevice = (PDFS_ATTACH_FILE_SYSTEM_OBJECT)
|
|||
|
FileSystemObject->AttachedDevice;
|
|||
|
attachedDevice != NULL;
|
|||
|
attachedDevice = (PDFS_ATTACH_FILE_SYSTEM_OBJECT)
|
|||
|
attachedDevice->DeviceObject.AttachedDevice) {
|
|||
|
|
|||
|
for (nextAFsoLink = DfsData.AFsoQueue.Flink;
|
|||
|
nextAFsoLink != &DfsData.AFsoQueue;
|
|||
|
nextAFsoLink = nextAFsoLink->Flink) {
|
|||
|
|
|||
|
candidateDevice = CONTAINING_RECORD(
|
|||
|
nextAFsoLink,
|
|||
|
DFS_ATTACH_FILE_SYSTEM_OBJECT,
|
|||
|
FsoLinks);
|
|||
|
|
|||
|
if (attachedDevice == candidateDevice) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Found Attached Device %08lx\n",
|
|||
|
candidateDevice);
|
|||
|
|
|||
|
RemoveEntryList( &attachedDevice->FsoLinks );
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
|
|||
|
IoDetachDevice( FileSystemObject );
|
|||
|
|
|||
|
IoDeleteDevice( (PDEVICE_OBJECT) attachedDevice );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Did not find a device attached to %08lx\n",
|
|||
|
FileSystemObject);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsDetachAllFileSystems
|
|||
|
//
|
|||
|
// Synopsis: Detaches from all file systems at unload time
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments: None
|
|||
|
//
|
|||
|
// Returns: Nothing
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsDetachAllFileSystems(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
PDFS_ATTACH_FILE_SYSTEM_OBJECT Device;
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
|
|||
|
FsRtlEnterFileSystem ();
|
|||
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|||
|
|
|||
|
while (!IsListEmpty (&DfsData.AFsoQueue)) {
|
|||
|
ListEntry = RemoveHeadList (&DfsData.AFsoQueue);
|
|||
|
Device = CONTAINING_RECORD(ListEntry,
|
|||
|
DFS_ATTACH_FILE_SYSTEM_OBJECT,
|
|||
|
FsoLinks);
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
FsRtlExitFileSystem ();
|
|||
|
|
|||
|
IoDetachDevice( Device->TargetDevice );
|
|||
|
|
|||
|
IoDeleteDevice( &Device->DeviceObject );
|
|||
|
|
|||
|
FsRtlEnterFileSystem ();
|
|||
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( &DfsData.Resource );
|
|||
|
FsRtlExitFileSystem ();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsSetupVdo, private
|
|||
|
//
|
|||
|
// Synopsis: A DFS volume device object is created and initialized. It is then
|
|||
|
// attached to the device object that is passed in.
|
|||
|
//
|
|||
|
// Arguments: [RootName] -- file path name of the root of the local
|
|||
|
// volume.
|
|||
|
// targetVdo -- The target device object we are attaching to.
|
|||
|
// realDevice -- the real device for this volume.
|
|||
|
// volNameLen -- Volume name length.
|
|||
|
// CreatedVdo -- The is the return value, from IoCreateDevice.
|
|||
|
//
|
|||
|
// Returns: [STATUS_INSUFFICIENT_RESOURCES] -- If unable to allocate
|
|||
|
// pool for provider name.
|
|||
|
// return status from IoCreateDevice or IoAttachDevice.
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsSetupVdo (
|
|||
|
IN PUNICODE_STRING RootName,
|
|||
|
IN PDEVICE_OBJECT targetVdo,
|
|||
|
IN PDEVICE_OBJECT realDevice,
|
|||
|
IN ULONG volNameLen,
|
|||
|
OUT PDFS_VOLUME_OBJECT *CreatedVdo
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
PDFS_VOLUME_OBJECT dfsVdo;
|
|||
|
|
|||
|
DebugTrace(1, Dbg, "DfsSetupVdo: Attempting to create device\n",0);
|
|||
|
Status = IoCreateDevice(
|
|||
|
DfsData.DriverObject,
|
|||
|
sizeof(DFS_VOLUME_OBJECT) - sizeof(DEVICE_OBJECT),
|
|||
|
NULL,
|
|||
|
FILE_DEVICE_DFS_VOLUME,
|
|||
|
targetVdo->Characteristics,
|
|||
|
FALSE,
|
|||
|
(PDEVICE_OBJECT *) &dfsVdo);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
dfsVdo->DeviceObject.StackSize = targetVdo->StackSize+1;
|
|||
|
dfsVdo->AttachCount = 1;
|
|||
|
dfsVdo->RealDevice = realDevice;
|
|||
|
|
|||
|
dfsVdo->Provider.NodeTypeCode = DFS_NTC_PROVIDER;
|
|||
|
dfsVdo->Provider.NodeByteSize = sizeof ( PROVIDER_DEF );
|
|||
|
dfsVdo->Provider.eProviderId = ++LocalProviderID;
|
|||
|
dfsVdo->Provider.fProvCapability = 0;
|
|||
|
dfsVdo->Provider.DeviceObject = targetVdo;
|
|||
|
dfsVdo->Provider.FileObject = NULL;
|
|||
|
dfsVdo->Provider.DeviceName.Buffer = (PWCHAR) ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
volNameLen,
|
|||
|
' sfD');
|
|||
|
|
|||
|
if (dfsVdo->Provider.DeviceName.Buffer == NULL) {
|
|||
|
IoDeleteDevice(&dfsVdo->DeviceObject);
|
|||
|
DebugTrace(-1, Dbg, "DfsSetupVdo: Cannot allocate memory\n", 0);
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(dfsVdo->Provider.DeviceName.Buffer, RootName->Buffer, volNameLen);
|
|||
|
|
|||
|
dfsVdo->Provider.DeviceName.MaximumLength =
|
|||
|
dfsVdo->Provider.DeviceName.Length =
|
|||
|
(USHORT)volNameLen;
|
|||
|
|
|||
|
//
|
|||
|
// If we successfully created the device object we can
|
|||
|
// begin the task of attaching.
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "DfsSetupVdo: Attempting to attach device\n",0);
|
|||
|
Status = IoAttachDeviceByPointer(
|
|||
|
&dfsVdo->DeviceObject,
|
|||
|
targetVdo);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ExFreePool(dfsVdo->Provider.DeviceName.Buffer);
|
|||
|
IoDeleteDevice(&dfsVdo->DeviceObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
*CreatedVdo = dfsVdo;
|
|||
|
}
|
|||
|
DebugTrace(-1, Dbg, "DfsSetupVdo: Returning status %p\n", ULongToPtr( Status ));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PDEVICE_OBJECT
|
|||
|
DfsGetDfsFilterDeviceObject(
|
|||
|
PFILE_OBJECT fileObject)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT DevObj;
|
|||
|
PDEVICE_OBJECT NextAttached;
|
|||
|
|
|||
|
DevObj = fileObject->Vpb->DeviceObject;
|
|||
|
NextAttached = DevObj->AttachedDevice;
|
|||
|
|
|||
|
while (NextAttached != NULL) {
|
|||
|
if (NextAttached->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|||
|
return NextAttached;
|
|||
|
}
|
|||
|
NextAttached = NextAttached->AttachedDevice;
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|