mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
1893 lines
62 KiB
C
1893 lines
62 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2011 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/filesystem/mountmgr/mountmgr.c
|
|
* PURPOSE: Mount Manager
|
|
* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
|
|
* Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
#include "mntmgr.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(INIT, MountmgrReadNoAutoMount)
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#endif
|
|
|
|
/* FIXME */
|
|
GUID MountedDevicesGuid = {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
|
|
|
|
PDEVICE_OBJECT gdeviceObject;
|
|
KEVENT UnloadEvent;
|
|
LONG Unloading;
|
|
|
|
static const WCHAR Cunc[] = L"\\??\\C:";
|
|
#define Cunc_LETTER_POSITION 4
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
IsOffline(PUNICODE_STRING SymbolicName)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG IsOffline, Default;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
|
|
/* Prepare to look in the registry to see if
|
|
* given volume is offline
|
|
*/
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].Name = SymbolicName->Buffer;
|
|
QueryTable[0].EntryContext = &IsOffline;
|
|
QueryTable[0].DefaultType = REG_DWORD;
|
|
QueryTable[0].DefaultLength = sizeof(ULONG);
|
|
QueryTable[0].DefaultData = &Default;
|
|
|
|
Default = 0;
|
|
|
|
/* Query status */
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
OfflinePath,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IsOffline = 0;
|
|
}
|
|
|
|
return (IsOffline != 0);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PSYMLINK_INFORMATION SymlinkInfo;
|
|
|
|
/* Browse all the symlinks to check if there is at least a drive letter */
|
|
for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
NextEntry != &DeviceInformation->SymbolicLinksListHead;
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
SymlinkInfo = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
if (IsDriveLetter(&SymlinkInfo->Name) && SymlinkInfo->Online)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN UCHAR Letter,
|
|
IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
/* Allocate a big enough buffer to contain the symbolic link */
|
|
DriveLetter->MaximumLength = DosDevices.Length + 3 * sizeof(WCHAR);
|
|
DriveLetter->Buffer = AllocatePool(DriveLetter->MaximumLength);
|
|
if (!DriveLetter->Buffer)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Copy prefix */
|
|
RtlCopyUnicodeString(DriveLetter, &DosDevices);
|
|
|
|
/* Update string to reflect real contents */
|
|
DriveLetter->Length = DosDevices.Length + 2 * sizeof(WCHAR);
|
|
DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 2] = UNICODE_NULL;
|
|
DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 1] = L':';
|
|
|
|
/* If caller wants a no drive entry */
|
|
if (Letter == (UCHAR)-1)
|
|
{
|
|
/* Then, create a no letter entry */
|
|
CreateNoDriveLetterEntry(UniqueId);
|
|
FreePool(DriveLetter->Buffer);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (Letter)
|
|
{
|
|
/* Use the letter given by the caller */
|
|
DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter;
|
|
Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* If caller didn't provide a letter, let's find one for him */
|
|
|
|
if (RtlPrefixUnicodeString(&DeviceFloppy, DeviceName, TRUE))
|
|
{
|
|
/* If the device is a floppy, start with letter A */
|
|
Letter = 'A';
|
|
}
|
|
else if (RtlPrefixUnicodeString(&DeviceCdRom, DeviceName, TRUE))
|
|
{
|
|
/* If the device is a CD-ROM, start with letter D */
|
|
Letter = 'D';
|
|
}
|
|
else
|
|
{
|
|
/* Finally, if it's a disk, use C */
|
|
Letter = 'C';
|
|
}
|
|
|
|
/* Try to affect a letter (up to Z, ofc) until it's possible */
|
|
for (; Letter <= 'Z'; Letter++)
|
|
{
|
|
DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter;
|
|
Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("Assigned drive %c: to %wZ\n", Letter, DeviceName);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* We failed to allocate a letter */
|
|
FreePool(DriveLetter->Buffer);
|
|
DPRINT("Failed to create a drive letter for %wZ\n", DeviceName);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
QueryDeviceInformation(IN PUNICODE_STRING SymbolicName,
|
|
OUT PUNICODE_STRING DeviceName OPTIONAL,
|
|
OUT PMOUNTDEV_UNIQUE_ID * UniqueId OPTIONAL,
|
|
OUT PBOOLEAN Removable OPTIONAL,
|
|
OUT PBOOLEAN GptDriveLetter OPTIONAL,
|
|
OUT PBOOLEAN HasGuid OPTIONAL,
|
|
IN OUT LPGUID StableGuid OPTIONAL,
|
|
OUT PBOOLEAN Valid OPTIONAL)
|
|
{
|
|
PIRP Irp;
|
|
USHORT Size;
|
|
KEVENT Event;
|
|
BOOLEAN IsRemovable;
|
|
PMOUNTDEV_NAME Name;
|
|
PMOUNTDEV_UNIQUE_ID Id;
|
|
PFILE_OBJECT FileObject;
|
|
PIO_STACK_LOCATION Stack;
|
|
NTSTATUS Status, IntStatus;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PARTITION_INFORMATION_EX PartitionInfo;
|
|
STORAGE_DEVICE_NUMBER StorageDeviceNumber;
|
|
VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes;
|
|
|
|
/* Get device associated with the symbolic name */
|
|
Status = IoGetDeviceObjectPointer(SymbolicName,
|
|
FILE_READ_ATTRIBUTES,
|
|
&FileObject,
|
|
&DeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
/* The associate FO can't have a file name */
|
|
if (FileObject->FileName.Length)
|
|
{
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
/* Check if it's removable & return to the user (if asked to) */
|
|
IsRemovable = (FileObject->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
|
|
if (Removable)
|
|
{
|
|
*Removable = IsRemovable;
|
|
}
|
|
|
|
/* Get the attached device */
|
|
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
|
|
|
|
/* If we've been asked for a GPT drive letter */
|
|
if (GptDriveLetter)
|
|
{
|
|
/* Consider it has one */
|
|
*GptDriveLetter = TRUE;
|
|
|
|
if (!IsRemovable)
|
|
{
|
|
/* Query the GPT attributes */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
&GptAttributes,
|
|
sizeof(GptAttributes),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
/* In case of failure, don't fail, that's no vital */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
/* Check if it has a drive letter */
|
|
else if (GptAttributes.GptAttributes & GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER)
|
|
{
|
|
*GptDriveLetter = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If caller wants to know if there's valid contents */
|
|
if (Valid)
|
|
{
|
|
/* Suppose it's not OK */
|
|
*Valid = FALSE;
|
|
|
|
if (!IsRemovable)
|
|
{
|
|
/* Query partitions information */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
&PartitionInfo,
|
|
sizeof(PartitionInfo),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
/* Once again here, failure isn't major */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
/* Verify we know something in */
|
|
else if (PartitionInfo.PartitionStyle == PARTITION_STYLE_MBR &&
|
|
IsRecognizedPartition(PartitionInfo.Mbr.PartitionType))
|
|
{
|
|
*Valid = TRUE;
|
|
}
|
|
|
|
/* It looks correct, ensure it is & query device number */
|
|
if (*Valid)
|
|
{
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
&StorageDeviceNumber,
|
|
sizeof(StorageDeviceNumber),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
*Valid = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If caller needs device name */
|
|
if (DeviceName)
|
|
{
|
|
/* Allocate a buffer just to request length */
|
|
Name = AllocatePool(sizeof(MOUNTDEV_NAME));
|
|
if (!Name)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Query device name */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
Name,
|
|
sizeof(MOUNTDEV_NAME),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
FreePool(Name);
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->FileObject = FileObject;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
/* Now, we've got the correct length */
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
Size = Name->NameLength + sizeof(MOUNTDEV_NAME);
|
|
|
|
FreePool(Name);
|
|
|
|
/* Allocate proper size */
|
|
Name = AllocatePool(Size);
|
|
if (!Name)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* And query name (for real that time) */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
Name,
|
|
Size,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
FreePool(Name);
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->FileObject = FileObject;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Copy back found name to the caller */
|
|
DeviceName->Length = Name->NameLength;
|
|
DeviceName->MaximumLength = Name->NameLength + sizeof(WCHAR);
|
|
DeviceName->Buffer = AllocatePool(DeviceName->MaximumLength);
|
|
if (!DeviceName->Buffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(DeviceName->Buffer, Name->Name, Name->NameLength);
|
|
DeviceName->Buffer[Name->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
|
|
}
|
|
}
|
|
|
|
FreePool(Name);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return Status;
|
|
}
|
|
|
|
/* If caller wants device unique ID */
|
|
if (UniqueId)
|
|
{
|
|
/* Prepare buffer to probe length */
|
|
Id = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID));
|
|
if (!Id)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Query unique ID length */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
Id,
|
|
sizeof(MOUNTDEV_UNIQUE_ID),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
FreePool(Id);
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->FileObject = FileObject;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
/* Retry with appropriate length */
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
Size = Id->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID);
|
|
|
|
FreePool(Id);
|
|
|
|
/* Allocate the correct buffer */
|
|
Id = AllocatePool(Size);
|
|
if (!Id)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Query unique ID */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
Id,
|
|
Size,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
FreePool(Id);
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->FileObject = FileObject;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
/* Hands back unique ID */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*UniqueId = Id;
|
|
}
|
|
else
|
|
{
|
|
/* In case of failure, also free the rest */
|
|
FreePool(Id);
|
|
if (DeviceName->Length)
|
|
{
|
|
FreePool(DeviceName->Buffer);
|
|
}
|
|
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* If user wants to know about GUID */
|
|
if (HasGuid)
|
|
{
|
|
/* Query device stable GUID */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
StableGuid,
|
|
sizeof(GUID),
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
if (!Irp)
|
|
{
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->FileObject = FileObject;
|
|
|
|
IntStatus = IoCallDriver(DeviceObject, Irp);
|
|
if (IntStatus == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
IntStatus = IoStatusBlock.Status;
|
|
}
|
|
|
|
*HasGuid = NT_SUCCESS(IntStatus);
|
|
}
|
|
|
|
ObDereferenceObject(DeviceObject);
|
|
ObDereferenceObject(FileObject);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING SymbolicName,
|
|
IN BOOLEAN DeviceNameGiven,
|
|
OUT PDEVICE_INFORMATION * DeviceInformation)
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY NextEntry;
|
|
UNICODE_STRING DeviceName;
|
|
PDEVICE_INFORMATION DeviceInfo = NULL;
|
|
|
|
/* If a device name was given, use it */
|
|
if (DeviceNameGiven)
|
|
{
|
|
DeviceName.Length = SymbolicName->Length;
|
|
DeviceName.Buffer = SymbolicName->Buffer;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, query it */
|
|
Status = QueryDeviceInformation(SymbolicName,
|
|
&DeviceName,
|
|
NULL, NULL,
|
|
NULL, NULL,
|
|
NULL, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Look for device information matching devive */
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->DeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
DeviceInfo = CONTAINING_RECORD(NextEntry,
|
|
DEVICE_INFORMATION,
|
|
DeviceListEntry);
|
|
|
|
if (RtlEqualUnicodeString(&DeviceName, &(DeviceInfo->DeviceName), TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Release our buffer if required */
|
|
if (!DeviceNameGiven)
|
|
{
|
|
FreePool(DeviceName.Buffer);
|
|
}
|
|
|
|
/* Return found information */
|
|
if (NextEntry == &(DeviceExtension->DeviceListHead))
|
|
{
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
*DeviceInformation = DeviceInfo;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
|
|
{
|
|
FreePool(DeviceInformation->SymbolicName.Buffer);
|
|
FreePool(DeviceInformation);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PSYMLINK_INFORMATION SymLink;
|
|
PUNIQUE_ID_REPLICATE UniqueId;
|
|
PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
|
|
|
|
/* Purge symbolic links list */
|
|
while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
|
|
SymLink = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
GlobalDeleteSymbolicLink(&(SymLink->Name));
|
|
FreePool(SymLink->Name.Buffer);
|
|
}
|
|
|
|
/* Purge replicated unique IDs list */
|
|
while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
|
|
UniqueId = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
|
|
|
|
FreePool(UniqueId->UniqueId);
|
|
FreePool(UniqueId);
|
|
}
|
|
|
|
while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
|
|
AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
|
|
|
|
FreePool(AssociatedDevice->String.Buffer);
|
|
FreePool(AssociatedDevice);
|
|
}
|
|
|
|
/* Free the rest of the buffers */
|
|
FreePool(DeviceInformation->SymbolicName.Buffer);
|
|
if (DeviceInformation->KeepLinks)
|
|
{
|
|
FreePool(DeviceInformation->UniqueId);
|
|
}
|
|
FreePool(DeviceInformation->DeviceName.Buffer);
|
|
|
|
/* Finally, stop waiting for notifications for this device */
|
|
if (DeviceInformation->TargetDeviceNotificationEntry)
|
|
{
|
|
IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
|
|
/* For all the saved links */
|
|
while (!IsListEmpty(&(SavedLinkInformation->SymbolicLinksListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(SavedLinkInformation->SymbolicLinksListHead));
|
|
SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
/* Remove from system & free */
|
|
GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
|
|
FreePool(SymlinkInformation->Name.Buffer);
|
|
FreePool(SymlinkInformation);
|
|
}
|
|
|
|
/* And free unique ID & entry */
|
|
FreePool(SavedLinkInformation->UniqueId);
|
|
FreePool(SavedLinkInformation);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
MountMgrUnload(IN struct _DRIVER_OBJECT *DriverObject)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PUNIQUE_ID_WORK_ITEM WorkItem;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_INFORMATION DeviceInformation;
|
|
PSAVED_LINK_INFORMATION SavedLinkInformation;
|
|
|
|
UNREFERENCED_PARAMETER(DriverObject);
|
|
|
|
/* Don't get notification any longer */
|
|
IoUnregisterShutdownNotification(gdeviceObject);
|
|
|
|
/* Free registry buffer */
|
|
DeviceExtension = gdeviceObject->DeviceExtension;
|
|
if (DeviceExtension->RegistryPath.Buffer)
|
|
{
|
|
FreePool(DeviceExtension->RegistryPath.Buffer);
|
|
DeviceExtension->RegistryPath.Buffer = NULL;
|
|
}
|
|
|
|
InterlockedExchange(&Unloading, TRUE);
|
|
|
|
KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
|
|
|
|
/* Wait for workers to finish */
|
|
if (InterlockedIncrement(&DeviceExtension->WorkerReferences) > 0)
|
|
{
|
|
KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
|
|
IO_NO_INCREMENT, 1, FALSE);
|
|
|
|
KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&(DeviceExtension->WorkerReferences));
|
|
}
|
|
|
|
/* Don't get any notification any longer² */
|
|
IoUnregisterPlugPlayNotification(DeviceExtension->NotificationEntry);
|
|
|
|
/* Acquire the driver exclusively */
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
|
|
FALSE, NULL);
|
|
|
|
/* Clear offline devices list */
|
|
while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
|
|
DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
MountMgrFreeDeadDeviceInfo(DeviceInformation);
|
|
}
|
|
|
|
/* Clear saved links list */
|
|
while (!IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceExtension->SavedLinksListHead));
|
|
SavedLinkInformation = CONTAINING_RECORD(NextEntry, SAVED_LINK_INFORMATION, SavedLinksListEntry);
|
|
MountMgrFreeSavedLink(SavedLinkInformation);
|
|
}
|
|
|
|
/* Clear workers list */
|
|
while (!IsListEmpty(&(DeviceExtension->UniqueIdWorkerItemListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead));
|
|
WorkItem = CONTAINING_RECORD(NextEntry, UNIQUE_ID_WORK_ITEM, UniqueIdWorkerItemListEntry);
|
|
|
|
KeClearEvent(&UnloadEvent);
|
|
WorkItem->Event = &UnloadEvent;
|
|
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
|
|
1, FALSE);
|
|
|
|
IoCancelIrp(WorkItem->Irp);
|
|
KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
|
|
|
|
IoFreeIrp(WorkItem->Irp);
|
|
FreePool(WorkItem->DeviceName.Buffer);
|
|
FreePool(WorkItem->IrpBuffer);
|
|
FreePool(WorkItem);
|
|
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
|
|
FALSE, NULL);
|
|
}
|
|
|
|
/* If we have drive letter data, release */
|
|
if (DeviceExtension->DriveLetterData)
|
|
{
|
|
FreePool(DeviceExtension->DriveLetterData);
|
|
DeviceExtension->DriveLetterData = NULL;
|
|
}
|
|
|
|
/* Release driver & quit */
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
|
|
GlobalDeleteSymbolicLink(&DosDevicesMount);
|
|
IoDeleteDevice(gdeviceObject);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Result, Default = 0;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
|
|
/* Simply read data from register */
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].Name = L"NoAutoMount";
|
|
QueryTable[0].EntryContext = &Result;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = &Default;
|
|
QueryTable[0].DefaultLength = sizeof(ULONG);
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryPath->Buffer,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return (Default != 0);
|
|
}
|
|
|
|
return (Result != 0);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING SymbolicName,
|
|
IN BOOLEAN ManuallyRegistered)
|
|
{
|
|
WCHAR Letter;
|
|
GUID StableGuid;
|
|
HANDLE LinkHandle;
|
|
ULONG SymLinkCount, i;
|
|
PLIST_ENTRY NextEntry;
|
|
PUNICODE_STRING SymLinks;
|
|
NTSTATUS Status, IntStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
PMOUNTDEV_UNIQUE_ID UniqueId, NewUniqueId;
|
|
PSAVED_LINK_INFORMATION SavedLinkInformation;
|
|
PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
|
|
WCHAR CSymLinkBuffer[RTL_NUMBER_OF(Cunc)], LinkTargetBuffer[MAX_PATH];
|
|
UNICODE_STRING TargetDeviceName, SuggestedLinkName, DeviceName, VolumeName, DriveLetter, LinkTarget, CSymLink;
|
|
BOOLEAN HasGuid, HasGptDriveLetter, Valid, UseOnlyIfThereAreNoOtherLinks, IsDrvLetter, IsOff, IsVolumeName, LinkError;
|
|
|
|
/* New device = new structure to represent it */
|
|
DeviceInformation = AllocatePool(sizeof(DEVICE_INFORMATION));
|
|
if (!DeviceInformation)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Initialise device structure */
|
|
RtlZeroMemory(DeviceInformation, sizeof(DEVICE_INFORMATION));
|
|
InitializeListHead(&(DeviceInformation->SymbolicLinksListHead));
|
|
InitializeListHead(&(DeviceInformation->ReplicatedUniqueIdsListHead));
|
|
InitializeListHead(&(DeviceInformation->AssociatedDevicesHead));
|
|
DeviceInformation->SymbolicName.Length = SymbolicName->Length;
|
|
DeviceInformation->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(UNICODE_NULL);
|
|
DeviceInformation->SymbolicName.Buffer = AllocatePool(DeviceInformation->SymbolicName.MaximumLength);
|
|
if (!DeviceInformation->SymbolicName.Buffer)
|
|
{
|
|
FreePool(DeviceInformation);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Copy symbolic name */
|
|
RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
|
|
DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
DeviceInformation->ManuallyRegistered = ManuallyRegistered;
|
|
DeviceInformation->DeviceExtension = DeviceExtension;
|
|
|
|
/* Query as much data as possible about device */
|
|
Status = QueryDeviceInformation(SymbolicName,
|
|
&TargetDeviceName,
|
|
&UniqueId,
|
|
&(DeviceInformation->Removable),
|
|
&HasGptDriveLetter,
|
|
&HasGuid,
|
|
&StableGuid,
|
|
&Valid);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
|
|
|
|
for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->OfflineDeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
if (RtlEqualUnicodeString(&(DeviceInformation->SymbolicName), &(CurrentDevice->SymbolicName), TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (NextEntry != &(DeviceExtension->OfflineDeviceListHead))
|
|
{
|
|
MountMgrFreeDeadDeviceInfo(DeviceInformation);
|
|
}
|
|
else
|
|
{
|
|
InsertTailList(&(DeviceExtension->OfflineDeviceListHead), &(DeviceInformation->DeviceListEntry));
|
|
}
|
|
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* Save gathered data */
|
|
DeviceInformation->UniqueId = UniqueId;
|
|
DeviceInformation->DeviceName = TargetDeviceName;
|
|
DeviceInformation->KeepLinks = FALSE;
|
|
|
|
/* If we found system partition, mark it */
|
|
if (DeviceExtension->DriveLetterData && UniqueId->UniqueIdLength == DeviceExtension->DriveLetterData->UniqueIdLength)
|
|
{
|
|
if (RtlCompareMemory(UniqueId->UniqueId, DeviceExtension->DriveLetterData->UniqueId, UniqueId->UniqueIdLength)
|
|
== UniqueId->UniqueIdLength)
|
|
{
|
|
IoSetSystemPartition(&TargetDeviceName);
|
|
}
|
|
}
|
|
|
|
/* Check suggested link name */
|
|
Status = QuerySuggestedLinkName(&(DeviceInformation->SymbolicName),
|
|
&SuggestedLinkName,
|
|
&UseOnlyIfThereAreNoOtherLinks);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SuggestedLinkName.Buffer = NULL;
|
|
}
|
|
|
|
/* If it's OK, set it and save its letter (if any) */
|
|
if (SuggestedLinkName.Buffer && IsDriveLetter(&SuggestedLinkName))
|
|
{
|
|
DeviceInformation->SuggestedDriveLetter = (UCHAR)SuggestedLinkName.Buffer[LETTER_POSITION];
|
|
}
|
|
|
|
/* Acquire driver exclusively */
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
|
|
|
|
/* Check if we already have device in to prevent double registration */
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->DeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
if (RtlEqualUnicodeString(&(CurrentDevice->DeviceName), &TargetDeviceName, TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we found it, clear ours, and return success, all correct */
|
|
if (NextEntry != &(DeviceExtension->DeviceListHead))
|
|
{
|
|
if (SuggestedLinkName.Buffer)
|
|
{
|
|
FreePool(SuggestedLinkName.Buffer);
|
|
}
|
|
|
|
FreePool(UniqueId);
|
|
FreePool(TargetDeviceName.Buffer);
|
|
FreePool(DeviceInformation->DeviceName.Buffer);
|
|
FreePool(DeviceInformation);
|
|
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Check if there are symlinks associated with our device in registry */
|
|
Status = QuerySymbolicLinkNamesFromStorage(DeviceExtension,
|
|
DeviceInformation,
|
|
(SuggestedLinkName.Buffer) ? &SuggestedLinkName : NULL,
|
|
UseOnlyIfThereAreNoOtherLinks,
|
|
&SymLinks,
|
|
&SymLinkCount,
|
|
HasGuid,
|
|
&StableGuid);
|
|
|
|
/* If our device is a CD-ROM */
|
|
if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
|
|
{
|
|
LinkTarget.Length = 0;
|
|
LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
|
|
LinkTarget.Buffer = LinkTargetBuffer;
|
|
|
|
RtlCopyMemory(CSymLinkBuffer, Cunc, sizeof(Cunc));
|
|
RtlInitUnicodeString(&CSymLink, CSymLinkBuffer);
|
|
|
|
/* Start checking all letters that could have been associated */
|
|
for (Letter = L'D'; Letter <= L'Z'; Letter++)
|
|
{
|
|
CSymLink.Buffer[Cunc_LETTER_POSITION] = Letter;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&CSymLink,
|
|
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Try to open the associated symlink */
|
|
Status = ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* And query its target */
|
|
Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL);
|
|
ZwClose(LinkHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
IntStatus = STATUS_UNSUCCESSFUL;
|
|
if (!RtlEqualUnicodeString(&LinkTarget, &DeviceInformation->DeviceName, FALSE))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* This link is matching our device, whereas it's not supposed to have any
|
|
* symlink associated.
|
|
* Delete it
|
|
*/
|
|
if (!SymLinkCount)
|
|
{
|
|
IoDeleteSymbolicLink(&CSymLink);
|
|
continue;
|
|
}
|
|
|
|
/* Now, for all the symlinks, check for ours */
|
|
for (i = 0; i < SymLinkCount; i++)
|
|
{
|
|
if (IsDriveLetter(&(SymLinks[i])))
|
|
{
|
|
/* If it exists, that's correct */
|
|
if (SymLinks[i].Buffer[LETTER_POSITION] == Letter)
|
|
{
|
|
IntStatus = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Useless link, delete it */
|
|
if (IntStatus == STATUS_UNSUCCESSFUL)
|
|
{
|
|
IoDeleteSymbolicLink(&CSymLink);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Suggested name is no longer required */
|
|
if (SuggestedLinkName.Buffer)
|
|
{
|
|
FreePool(SuggestedLinkName.Buffer);
|
|
}
|
|
|
|
/* If if failed, ensure we don't take symlinks into account */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SymLinks = NULL;
|
|
SymLinkCount = 0;
|
|
}
|
|
|
|
/* Now we queried them, remove the symlinks */
|
|
SavedLinkInformation = RemoveSavedLinks(DeviceExtension, UniqueId);
|
|
|
|
IsDrvLetter = FALSE;
|
|
IsOff = FALSE;
|
|
IsVolumeName = FALSE;
|
|
/* For all the symlinks */
|
|
for (i = 0; i < SymLinkCount; i++)
|
|
{
|
|
/* Check if our device is a volume */
|
|
if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks[i])))
|
|
{
|
|
IsVolumeName = TRUE;
|
|
}
|
|
/* If it has a drive letter */
|
|
else if (IsDriveLetter(&(SymLinks[i])))
|
|
{
|
|
if (IsDrvLetter)
|
|
{
|
|
DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
IsDrvLetter = TRUE;
|
|
}
|
|
}
|
|
|
|
/* And recreate the symlink to our device */
|
|
Status = GlobalCreateSymbolicLink(&(SymLinks[i]), &TargetDeviceName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
LinkError = TRUE;
|
|
|
|
if ((SavedLinkInformation && !RedirectSavedLink(SavedLinkInformation, &(SymLinks[i]), &TargetDeviceName)) ||
|
|
!SavedLinkInformation)
|
|
{
|
|
Status = QueryDeviceInformation(&(SymLinks[i]), &DeviceName, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
LinkError = RtlEqualUnicodeString(&TargetDeviceName, &DeviceName, TRUE);
|
|
FreePool(DeviceName.Buffer);
|
|
}
|
|
|
|
if (!LinkError)
|
|
{
|
|
if (IsDriveLetter(&(SymLinks[i])))
|
|
{
|
|
IsDrvLetter = FALSE;
|
|
DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
|
|
}
|
|
|
|
FreePool(SymLinks[i].Buffer);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if was offline */
|
|
if (IsOffline(&(SymLinks[i])))
|
|
{
|
|
IsOff = TRUE;
|
|
}
|
|
|
|
/* Finally, associate this symlink with the device */
|
|
SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
|
|
if (!SymlinkInformation)
|
|
{
|
|
GlobalDeleteSymbolicLink(&(SymLinks[i]));
|
|
FreePool(SymLinks[i].Buffer);
|
|
continue;
|
|
}
|
|
|
|
SymlinkInformation->Name = SymLinks[i];
|
|
SymlinkInformation->Online = TRUE;
|
|
|
|
InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
|
|
&(SymlinkInformation->SymbolicLinksListEntry));
|
|
}
|
|
|
|
/* Now, for all the recreated symlinks, notify their recreation */
|
|
for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
NextEntry != &(DeviceInformation->SymbolicLinksListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
SendLinkCreated(&(SymlinkInformation->Name));
|
|
}
|
|
|
|
/* If we had saved links, it's time to free them */
|
|
if (SavedLinkInformation)
|
|
{
|
|
MountMgrFreeSavedLink(SavedLinkInformation);
|
|
}
|
|
|
|
/* If our device doesn't have a volume name */
|
|
if (!IsVolumeName)
|
|
{
|
|
/* It's time to create one */
|
|
Status = CreateNewVolumeName(&VolumeName, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Write it to global database */
|
|
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
DatabasePath,
|
|
VolumeName.Buffer,
|
|
REG_BINARY,
|
|
UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength);
|
|
|
|
/* And create the symlink */
|
|
GlobalCreateSymbolicLink(&VolumeName, &TargetDeviceName);
|
|
|
|
SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
|
|
if (!SymlinkInformation)
|
|
{
|
|
FreePool(VolumeName.Buffer);
|
|
}
|
|
/* Finally, associate it with the device and notify creation */
|
|
else
|
|
{
|
|
SymlinkInformation->Name = VolumeName;
|
|
SymlinkInformation->Online = TRUE;
|
|
InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
|
|
&(SymlinkInformation->SymbolicLinksListEntry));
|
|
|
|
SendLinkCreated(&VolumeName);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we found a drive letter, then, ignore the suggested one */
|
|
if (IsDrvLetter)
|
|
{
|
|
DeviceInformation->SuggestedDriveLetter = 0;
|
|
}
|
|
/* Else, it's time to set up one */
|
|
else if ((DeviceExtension->NoAutoMount || DeviceInformation->Removable) &&
|
|
DeviceExtension->AutomaticDriveLetter &&
|
|
(HasGptDriveLetter || DeviceInformation->SuggestedDriveLetter) &&
|
|
!HasNoDriveLetterEntry(UniqueId))
|
|
{
|
|
/* Create a new drive letter */
|
|
Status = CreateNewDriveLetterName(&DriveLetter, &TargetDeviceName,
|
|
DeviceInformation->SuggestedDriveLetter,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
CreateNoDriveLetterEntry(UniqueId);
|
|
}
|
|
else
|
|
{
|
|
/* Save it to global database */
|
|
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
DatabasePath,
|
|
DriveLetter.Buffer,
|
|
REG_BINARY,
|
|
UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength);
|
|
|
|
/* Associate it with the device and notify creation */
|
|
SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
|
|
if (!SymlinkInformation)
|
|
{
|
|
FreePool(DriveLetter.Buffer);
|
|
}
|
|
else
|
|
{
|
|
SymlinkInformation->Name = DriveLetter;
|
|
SymlinkInformation->Online = TRUE;
|
|
InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
|
|
&(SymlinkInformation->SymbolicLinksListEntry));
|
|
|
|
SendLinkCreated(&DriveLetter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If that's a PnP device, register for notifications */
|
|
if (!ManuallyRegistered)
|
|
{
|
|
RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation);
|
|
}
|
|
|
|
/* Finally, insert the device into our devices list */
|
|
InsertTailList(&(DeviceExtension->DeviceListHead), &(DeviceInformation->DeviceListEntry));
|
|
|
|
/* Copy device unique ID */
|
|
NewUniqueId = AllocatePool(UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
|
|
if (NewUniqueId)
|
|
{
|
|
NewUniqueId->UniqueIdLength = UniqueId->UniqueIdLength;
|
|
RtlCopyMemory(NewUniqueId->UniqueId, UniqueId->UniqueId, UniqueId->UniqueIdLength);
|
|
}
|
|
|
|
/* If device's offline or valid, skip its notifications */
|
|
if (IsOff || Valid)
|
|
{
|
|
DeviceInformation->SkipNotifications = TRUE;
|
|
}
|
|
|
|
/* In case device is valid and is set to no automount,
|
|
* set it offline.
|
|
*/
|
|
if (DeviceExtension->NoAutoMount || IsDrvLetter)
|
|
{
|
|
IsOff = !DeviceInformation->SkipNotifications;
|
|
}
|
|
else
|
|
{
|
|
IsOff = FALSE;
|
|
}
|
|
|
|
/* Finally, release the exclusive lock */
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
|
|
/* If device is not offline, notify its arrival */
|
|
if (!IsOff)
|
|
{
|
|
SendOnlineNotification(SymbolicName);
|
|
}
|
|
|
|
/* If we had symlinks (from storage), free them */
|
|
if (SymLinks)
|
|
{
|
|
FreePool(SymLinks);
|
|
}
|
|
|
|
/* Notify about unique id change */
|
|
if (NewUniqueId)
|
|
{
|
|
IssueUniqueIdChangeNotify(DeviceExtension, SymbolicName, NewUniqueId);
|
|
FreePool(NewUniqueId);
|
|
}
|
|
|
|
/* If this drive was set to have a drive letter automatically
|
|
* Now it's back, local databases sync will be required
|
|
*/
|
|
if (DeviceExtension->AutomaticDriveLetter)
|
|
{
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
|
|
|
|
ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
|
|
|
|
NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
while (CurrentDevice != DeviceInformation)
|
|
{
|
|
if (!CurrentDevice->NoDatabase)
|
|
{
|
|
ReconcileThisDatabaseWithMaster(DeviceExtension, CurrentDevice);
|
|
}
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
}
|
|
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING DeviceName)
|
|
{
|
|
PLIST_ENTRY NextEntry, DeviceEntry;
|
|
PUNIQUE_ID_REPLICATE UniqueIdReplicate;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
|
|
PSAVED_LINK_INFORMATION SavedLinkInformation = NULL;
|
|
PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
|
|
|
|
/* Acquire device exclusively */
|
|
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
|
|
|
|
/* Look for the leaving device */
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->DeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
if (!RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we found it */
|
|
if (NextEntry != &(DeviceExtension->DeviceListHead))
|
|
{
|
|
/* If it's asked to keep links, then, prepare to save them */
|
|
if (DeviceInformation->KeepLinks)
|
|
{
|
|
SavedLinkInformation = AllocatePool(sizeof(SAVED_LINK_INFORMATION));
|
|
if (!SavedLinkInformation)
|
|
{
|
|
DeviceInformation->KeepLinks = FALSE;
|
|
}
|
|
}
|
|
|
|
/* If it's possible (and asked), start to save them */
|
|
if (DeviceInformation->KeepLinks)
|
|
{
|
|
InsertTailList(&(DeviceExtension->SavedLinksListHead), &(SavedLinkInformation->SavedLinksListEntry));
|
|
InitializeListHead(&(SavedLinkInformation->SymbolicLinksListHead));
|
|
SavedLinkInformation->UniqueId = DeviceInformation->UniqueId;
|
|
}
|
|
|
|
/* For all the symlinks */
|
|
while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
|
|
SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
/* If we have to, save the link */
|
|
if (DeviceInformation->KeepLinks)
|
|
{
|
|
InsertTailList(&(SavedLinkInformation->SymbolicLinksListHead), &(SymlinkInformation->SymbolicLinksListEntry));
|
|
}
|
|
/* Otherwise, just release it */
|
|
else
|
|
{
|
|
GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
|
|
FreePool(SymlinkInformation->Name.Buffer);
|
|
FreePool(SymlinkInformation);
|
|
}
|
|
}
|
|
|
|
/* Free all the replicated unique IDs */
|
|
while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
|
|
UniqueIdReplicate = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
|
|
|
|
|
|
FreePool(UniqueIdReplicate->UniqueId);
|
|
FreePool(UniqueIdReplicate);
|
|
}
|
|
|
|
while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
|
|
{
|
|
NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
|
|
AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
|
|
|
|
DeviceInformation->NoDatabase = TRUE;
|
|
FreePool(AssociatedDevice->String.Buffer);
|
|
FreePool(AssociatedDevice);
|
|
}
|
|
|
|
/* Remove device from the device list */
|
|
RemoveEntryList(&(DeviceInformation->DeviceListEntry));
|
|
|
|
/* If there are still devices, check if some were associated with ours */
|
|
if (!IsListEmpty(&(DeviceInformation->DeviceListEntry)))
|
|
{
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->DeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
/* And then, remove them */
|
|
DeviceEntry = CurrentDevice->AssociatedDevicesHead.Flink;
|
|
while (DeviceEntry != &(CurrentDevice->AssociatedDevicesHead))
|
|
{
|
|
AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
|
|
DeviceEntry = DeviceEntry->Flink;
|
|
|
|
if (AssociatedDevice->DeviceInformation != DeviceInformation)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
RemoveEntryList(&(AssociatedDevice->AssociatedDevicesEntry));
|
|
FreePool(AssociatedDevice->String.Buffer);
|
|
FreePool(AssociatedDevice);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Finally, clean up device name, symbolic name */
|
|
FreePool(DeviceInformation->SymbolicName.Buffer);
|
|
if (!DeviceInformation->KeepLinks)
|
|
{
|
|
FreePool(DeviceInformation->UniqueId);
|
|
}
|
|
FreePool(DeviceInformation->DeviceName.Buffer);
|
|
|
|
/* Unregister notifications */
|
|
if (DeviceInformation->TargetDeviceNotificationEntry)
|
|
{
|
|
IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
|
|
}
|
|
|
|
/* And leave */
|
|
FreePool(DeviceInformation);
|
|
}
|
|
else
|
|
{
|
|
/* We didn't find device, perhaps because it was offline */
|
|
for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
|
|
NextEntry != &(DeviceExtension->OfflineDeviceListHead);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
/* It was, remove it */
|
|
if (RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE) == 0)
|
|
{
|
|
RemoveEntryList(&(DeviceInformation->DeviceListEntry));
|
|
MountMgrFreeDeadDeviceInfo(DeviceInformation);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Release driver */
|
|
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
MountMgrMountedDeviceNotification(IN PVOID NotificationStructure,
|
|
IN PVOID Context)
|
|
{
|
|
BOOLEAN OldState;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
|
|
|
|
/* Notification for a device arrived */
|
|
/* Disable hard errors */
|
|
OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
|
|
PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
|
|
|
|
DeviceExtension = Context;
|
|
Notification = NotificationStructure;
|
|
|
|
/* Dispatch according to the event */
|
|
if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_ARRIVAL))
|
|
{
|
|
MountMgrMountedDeviceArrival(DeviceExtension, Notification->SymbolicLinkName, FALSE);
|
|
}
|
|
else if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_REMOVAL))
|
|
{
|
|
MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
|
|
}
|
|
|
|
/* Reset hard errors */
|
|
PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION Stack;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Allow driver opening for communication
|
|
* as long as it's not taken for a directory
|
|
*/
|
|
if (Stack->MajorFunction == IRP_MJ_CREATE &&
|
|
Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
|
|
{
|
|
Status = STATUS_NOT_A_DIRECTORY;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
MountMgrCancel(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIRP ListIrp;
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY NextEntry;
|
|
PFILE_OBJECT FileObject;
|
|
PIO_STACK_LOCATION Stack;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
FileObject = Stack->FileObject;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
/* If IRP list if empty, it's OK */
|
|
if (IsListEmpty(&(DeviceExtension->IrpListHead)))
|
|
{
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Otherwise, cancel all the IRPs */
|
|
NextEntry = DeviceExtension->IrpListHead.Flink;
|
|
do
|
|
{
|
|
ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
|
|
if (IoGetCurrentIrpStackLocation(ListIrp)->FileObject == FileObject)
|
|
{
|
|
ListIrp->Cancel = TRUE;
|
|
ListIrp->CancelIrql = OldIrql;
|
|
ListIrp->CancelRoutine = NULL;
|
|
MountMgrCancel(DeviceObject, ListIrp);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
}
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
while (NextEntry != &(DeviceExtension->IrpListHead));
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
InterlockedExchange(&Unloading, TRUE);
|
|
|
|
KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
|
|
|
|
/* Wait for workers */
|
|
if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)) > 0)
|
|
{
|
|
KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
|
|
IO_NO_INCREMENT,
|
|
1,
|
|
FALSE);
|
|
KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&(DeviceExtension->WorkerReferences));
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
NTSTATUS Status;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, DatabasePath);
|
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
&DeviceMount,
|
|
FILE_DEVICE_NETWORK,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
&DeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
DriverObject->DriverUnload = MountMgrUnload;
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION));
|
|
DeviceExtension->DeviceObject = DeviceObject;
|
|
DeviceExtension->DriverObject = DriverObject;
|
|
|
|
InitializeListHead(&(DeviceExtension->DeviceListHead));
|
|
InitializeListHead(&(DeviceExtension->OfflineDeviceListHead));
|
|
|
|
KeInitializeSemaphore(&(DeviceExtension->DeviceLock), 1, 1);
|
|
KeInitializeSemaphore(&(DeviceExtension->RemoteDatabaseLock), 1, 1);
|
|
|
|
InitializeListHead(&(DeviceExtension->IrpListHead));
|
|
DeviceExtension->EpicNumber = 1;
|
|
|
|
InitializeListHead(&(DeviceExtension->SavedLinksListHead));
|
|
|
|
InitializeListHead(&(DeviceExtension->WorkerQueueListHead));
|
|
KeInitializeSemaphore(&(DeviceExtension->WorkerSemaphore), 0, MAXLONG);
|
|
DeviceExtension->WorkerReferences = -1;
|
|
KeInitializeSpinLock(&(DeviceExtension->WorkerLock));
|
|
|
|
InitializeListHead(&(DeviceExtension->UniqueIdWorkerItemListHead));
|
|
InitializeListHead(&(DeviceExtension->OnlineNotificationListHead));
|
|
DeviceExtension->OnlineNotificationCount = 1;
|
|
|
|
DeviceExtension->RegistryPath.Length = RegistryPath->Length;
|
|
DeviceExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
|
|
DeviceExtension->RegistryPath.Buffer = AllocatePool(DeviceExtension->RegistryPath.MaximumLength);
|
|
if (!DeviceExtension->RegistryPath.Buffer)
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyUnicodeString(&(DeviceExtension->RegistryPath), RegistryPath);
|
|
|
|
DeviceExtension->NoAutoMount = MountmgrReadNoAutoMount(&(DeviceExtension->RegistryPath));
|
|
|
|
GlobalCreateSymbolicLink(&DosDevicesMount, &DeviceMount);
|
|
|
|
/* Register for device arrival & removal. Ask to be notified for already
|
|
* present devices
|
|
*/
|
|
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
|
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|
&MountedDevicesGuid,
|
|
DriverObject,
|
|
MountMgrMountedDeviceNotification,
|
|
DeviceExtension,
|
|
&(DeviceExtension->NotificationEntry));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
return Status;
|
|
}
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] =
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MountMgrCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MountMgrDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MountMgrCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = MountMgrShutdown;
|
|
|
|
gdeviceObject = DeviceObject;
|
|
|
|
Status = IoRegisterShutdownNotification(DeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
|
|
return Status;
|
|
}
|