|
|
//+----------------------------------------------------------------------------
//
// 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; }
|