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

1160 lines
34 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+----------------------------------------------------------------------------
//
// 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;
}