[MOUNTMGR]

Finally add the long awaited Mount Point Manager (aka mountmgr).
It's not complete yet, but will do most of the job it's been designed for.
What's missing is some dos volumes handlers, complete database support (local - registry - is complete, remote - files - is not).
It handles NTFS properties like reparse points.
It also handles devices with drive letters and those without drive letters (by using their unique ID).
Devices removal/arrival is detected through notifications (might be an issue).
Some work will have to be done in storage stack to fully support it.
Most of its IOCTL have been implemented (it's possible, for example, to notify a volume arrival through them, in case notifications don't work).

There's still some work to do on it to have it complete and fully implemented.
Enjoy!


svn path=/branches/usb-bringup-trunk/; revision=55156
This commit is contained in:
Pierre Schweitzer 2012-01-24 22:54:14 +00:00
parent 2f5db208de
commit 31572e7770
15 changed files with 8258 additions and 0 deletions

View file

@ -4,6 +4,7 @@ add_subdirectory(battery)
add_subdirectory(bus)
add_subdirectory(directx)
add_subdirectory(filesystems)
add_subdirectory(filters)
add_subdirectory(hid)
add_subdirectory(input)
add_subdirectory(ksfilter)

View file

@ -19,6 +19,9 @@
<directory name="filesystems">
<xi:include href="filesystems/directory.rbuild" />
</directory>
<directory name="filters>
<xi:include href="filters/directory.rbuild" />
</directory>
<directory name="input">
<xi:include href="input/directory.rbuild" />
</directory>

View file

@ -0,0 +1,2 @@
add_subdirectory(mountmgr)

View file

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE group SYSTEM "../../tools/rbuild/project.dtd">
<group xmlns:xi="http://www.w3.org/2001/XInclude">
<directory name="mountmgr">
<xi:include href="mountmgr/mountmgr.rbuild" />
</directory>
</group>

View file

@ -0,0 +1,21 @@
list(APPEND SOURCE
database.c
device.c
mountmgr.c
notify.c
point.c
symlink.c
uniqueid.c
mountmgr.rc)
allow_warnings(mountmgr)
add_library(mountmgr SHARED ${SOURCE})
set_module_type(mountmgr kernelmodedriver)
add_importlibs(mountmgr ntoskrnl hal)
add_pch(mountmgr mntmgr.h)
#add_cd_file(TARGET mountmgr DESTINATION reactos/system32/drivers NO_CAB FOR all)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,452 @@
#ifndef _MNTMGR_H_
#define _MNTMGR_H_
#include <ntifs.h>
#include <ntddk.h>
#include <mountdev.h>
#include <ntddvol.h>
#include <wdmguid.h>
#include <ioevent.h>
#include <psfuncs.h>
#include <ntdddisk.h>
#include <ntddvol.h>
/* Enter FIXME */
#ifdef IsEqualGUID
#undef IsEqualGUID
#endif
#define IsEqualGUID(rguid1, rguid2) (!RtlCompareMemory(rguid1, rguid2, sizeof(GUID)))
#define FILE_READ_PROPERTIES 0x00000008
#define FILE_WRITE_PROPERTIES 0x00000010
#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER 0x80000000
/* Leave FIXME */
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT DeviceObject; // 0x0
PDRIVER_OBJECT DriverObject; // 0x4
LIST_ENTRY DeviceListHead; // 0x8
LIST_ENTRY OfflineDeviceListHead; // 0x10
PVOID NotificationEntry; // 0x18
KSEMAPHORE DeviceLock; // 0x1C
KSEMAPHORE RemoteDatabaseLock; // 0x30
ULONG AutomaticDriveLetter; // 0x44
LIST_ENTRY IrpListHead; // 0x48
ULONG EpicNumber; // 0x50
LIST_ENTRY SavedLinksListHead; // 0x54
BOOLEAN ProcessedSuggestions; // 0x5C
BOOLEAN NoAutoMount; // 0x5D
LIST_ENTRY WorkerQueueListHead; // 0x60
KSEMAPHORE WorkerSemaphore; // 0x68
LONG WorkerReferences; // 0x7C
KSPIN_LOCK WorkerLock; // 0x80
LIST_ENTRY UniqueIdWorkerItemListHead; // 0x84
PMOUNTDEV_UNIQUE_ID DriveLetterData; // 0x8C
UNICODE_STRING RegistryPath; // 0x90
LONG WorkerThreadStatus; // 0x98
LIST_ENTRY OnlineNotificationListHead; // 0x9C
ULONG OnlineNotificationWorkerActive; // 0xA4
ULONG OnlineNotificationCount; // 0xA8
KEVENT OnlineNotificationEvent; // 0xAC
} DEVICE_EXTENSION, *PDEVICE_EXTENSION; // 0xBC
typedef struct _DEVICE_INFORMATION
{
LIST_ENTRY DeviceListEntry; // 0x00
LIST_ENTRY SymbolicLinksListHead; // 0x08
LIST_ENTRY ReplicatedUniqueIdsListHead; // 0x10
LIST_ENTRY AssociatedDevicesHead; // 0x18
UNICODE_STRING SymbolicName; // 0x20
PMOUNTDEV_UNIQUE_ID UniqueId; // 0x28
UNICODE_STRING DeviceName; // 0x2C
BOOLEAN KeepLinks; // 0x34
UCHAR SuggestedDriveLetter; // 0x35
BOOLEAN Volume; // 0x36
BOOLEAN Removable; // 0x37
BOOLEAN LetterAssigned; // 0x38
BOOLEAN NeedsReconcile; // 0x39
BOOLEAN NoDatabase; // 0x3A
BOOLEAN SkipNotifications; // 0x3B
ULONG Migrated; // 0x3C
LONG MountState; // 0x40
PVOID TargetDeviceNotificationEntry; // 0x44
PDEVICE_EXTENSION DeviceExtension; // 0x48
} DEVICE_INFORMATION, *PDEVICE_INFORMATION; // 0x4C
typedef struct _SYMLINK_INFORMATION
{
LIST_ENTRY SymbolicLinksListEntry; // 0x00
UNICODE_STRING Name; // 0x08
BOOLEAN Online; // 0x10
} SYMLINK_INFORMATION, *PSYMLINK_INFORMATION; // 0x14
typedef struct _SAVED_LINK_INFORMATION
{
LIST_ENTRY SavedLinksListEntry; // 0x0
LIST_ENTRY SymbolicLinksListHead; // 0x8
PMOUNTDEV_UNIQUE_ID UniqueId; // 0x10
} SAVED_LINK_INFORMATION, *PSAVED_LINK_INFORMATION; // 0x14
typedef struct _UNIQUE_ID_REPLICATE
{
LIST_ENTRY ReplicatedUniqueIdsListEntry; // 0x0
PMOUNTDEV_UNIQUE_ID UniqueId; // 0x8
} UNIQUE_ID_REPLICATE, *PUNIQUE_ID_REPLICATE; // 0xC
typedef struct _DATABASE_ENTRY
{
ULONG EntrySize; // 0x00
ULONG DatabaseOffset; // 0x04
USHORT SymbolicNameOffset; // 0x08
USHORT SymbolicNameLength; // 0x0A
USHORT UniqueIdOffset; // 0x0C
USHORT UniqueIdLength; // 0x0E
} DATABASE_ENTRY, *PDATABASE_ENTRY; // 0x10
typedef struct _ASSOCIATED_DEVICE_ENTRY
{
LIST_ENTRY AssociatedDevicesEntry; // 0x00
PDEVICE_INFORMATION DeviceInformation; // 0x08
UNICODE_STRING String; // 0x0C
} ASSOCIATED_DEVICE_ENTRY, *PASSOCIATED_DEVICE_ENTRY; // 0x14
typedef struct _ONLINE_NOTIFICATION_WORK_ITEM
{
WORK_QUEUE_ITEM; // 0x00
PDEVICE_EXTENSION DeviceExtension; // 0x10
UNICODE_STRING SymbolicName; // 0x14
} ONLINE_NOTIFICATION_WORK_ITEM, *PONLINE_NOTIFICATION_WORK_ITEM; // 0x1C
typedef struct _RECONCILE_WORK_ITEM
{
LIST_ENTRY WorkerQueueListEntry; // 0x00
PIO_WORKITEM WorkItem; // 0x08
PWORKER_THREAD_ROUTINE WorkerRoutine; // 0x0C
PVOID Context; // 0x10
PDEVICE_EXTENSION DeviceExtension; // 0x14
PDEVICE_INFORMATION DeviceInformation; // 0x18
} RECONCILE_WORK_ITEM, *PRECONCILE_WORK_ITEM; // 0x1C
typedef struct _MIGRATE_WORK_ITEM
{
PIO_WORKITEM WorkItem; // 0x0
PDEVICE_INFORMATION DeviceInformation; // 0x4
PKEVENT Event; // 0x8
NTSTATUS Status; // 0x0C
HANDLE Database; // 0x10
} MIGRATE_WORK_ITEM, *PMIGRATE_WORK_ITEM; // 0x14
typedef struct _UNIQUE_ID_WORK_ITEM
{
LIST_ENTRY UniqueIdWorkerItemListEntry; // 0x0
PIO_WORKITEM WorkItem; // 0x8
PDEVICE_EXTENSION DeviceExtension; // 0xC
PIRP Irp; // 0x10
PVOID IrpBuffer; // 0x14
PKEVENT Event; // 0x1C
UNICODE_STRING DeviceName; // 0x20
ULONG IrpBufferLength; // 0x28
ULONG StackSize; // 0x2C
} UNIQUE_ID_WORK_ITEM, *PUNIQUE_ID_WORK_ITEM; // 0x30
PDEVICE_OBJECT gdeviceObject;
/* Memory allocation helpers */
#define AllocatePool(Size) ExAllocatePoolWithTag(PagedPool, Size, 'AtnM')
#define FreePool(P) ExFreePoolWithTag(P, 'AtnM')
/* Misc macros */
#define MAX(a, b) ((a > b) ? a : b)
#define LETTER_POSITION 0xC
#define COLON_POSITION 0xD
#define DRIVE_LETTER_LENGTH 0x1C
/* mountmgr.c */
extern UNICODE_STRING DosDevicesMount;
extern UNICODE_STRING ReparseIndex;
extern UNICODE_STRING DeviceFloppy;
extern UNICODE_STRING DeviceMount;
extern UNICODE_STRING DeviceCdRom;
extern UNICODE_STRING SafeVolumes;
extern UNICODE_STRING DosDevices;
extern UNICODE_STRING DosGlobal;
extern UNICODE_STRING Global;
extern UNICODE_STRING Volume;
extern KEVENT UnloadEvent;
extern LONG Unloading;
DRIVER_INITIALIZE DriverEntry;
VOID
MountMgrCancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
MountMgrMountedDeviceArrival(
IN PDEVICE_EXTENSION Extension,
IN PUNICODE_STRING SymbolicName,
IN BOOLEAN FromVolume
);
VOID
MountMgrMountedDeviceRemoval(
IN PDEVICE_EXTENSION Extension,
IN PUNICODE_STRING DeviceName
);
NTSTATUS
FindDeviceInfo(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
IN BOOLEAN DeviceNameGiven,
OUT PDEVICE_INFORMATION * DeviceInformation
);
VOID
MountMgrFreeDeadDeviceInfo(
IN PDEVICE_INFORMATION DeviceInformation
);
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
);
BOOLEAN
HasDriveLetter(
IN PDEVICE_INFORMATION DeviceInformation
);
/* database.c */
extern PWSTR DatabasePath;
extern PWSTR OfflinePath;
VOID
ReconcileThisDatabaseWithMaster(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_INFORMATION DeviceInformation
);
NTSTATUS
WaitForRemoteDatabaseSemaphore(
IN PDEVICE_EXTENSION DeviceExtension
);
VOID
ReleaseRemoteDatabaseSemaphore(
IN PDEVICE_EXTENSION DeviceExtension
);
VOID
ChangeRemoteDatabaseUniqueId(
IN PDEVICE_INFORMATION DeviceInformation,
IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
IN PMOUNTDEV_UNIQUE_ID NewUniqueId
);
VOID
ReconcileAllDatabasesWithMaster(
IN PDEVICE_EXTENSION DeviceExtension
);
VOID
DeleteFromLocalDatabase(
IN PUNICODE_STRING SymbolicLink,
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
VOID
DeleteRegistryDriveLetter(
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
VOID
DeleteNoDriveLetterEntry(
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
NTSTATUS
QueryVolumeName(
IN HANDLE RootDirectory,
IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
IN PUNICODE_STRING FileName OPTIONAL,
OUT PUNICODE_STRING SymbolicName,
OUT PUNICODE_STRING VolumeName
);
/* device.c */
DRIVER_DISPATCH MountMgrDeviceControl;
/* notify.c */
VOID
IssueUniqueIdChangeNotifyWorker(
IN PUNIQUE_ID_WORK_ITEM WorkItem,
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
VOID
WaitForOnlinesToComplete(
IN PDEVICE_EXTENSION DeviceExtension
);
VOID
RegisterForTargetDeviceNotification(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_INFORMATION DeviceInformation
);
VOID
SendOnlineNotification(
IN PUNICODE_STRING SymbolicName
);
VOID
IssueUniqueIdChangeNotify(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING DeviceName,
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
VOID
PostOnlineNotification(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName
);
VOID
MountMgrNotify(
IN PDEVICE_EXTENSION DeviceExtension
);
VOID
MountMgrNotifyNameChange(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING DeviceName,
IN BOOLEAN ValidateVolume
);
/* uniqueid.c */
VOID
MountMgrUniqueIdChangeRoutine(
IN PDEVICE_EXTENSION DeviceExtension,
IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
IN PMOUNTDEV_UNIQUE_ID NewUniqueId
);
VOID
CreateNoDriveLetterEntry(
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
BOOLEAN
HasNoDriveLetterEntry(
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
/* point.c */
NTSTATUS
MountMgrCreatePointWorker(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName
);
NTSTATUS
QueryPointsFromSymbolicLinkName(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
IN PIRP Irp
);
NTSTATUS
QueryPointsFromMemory(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL,
IN PUNICODE_STRING SymbolicName OPTIONAL
);
/* symlink.c */
NTSTATUS
GlobalCreateSymbolicLink(
IN PUNICODE_STRING DosName,
IN PUNICODE_STRING DeviceName
);
NTSTATUS
GlobalDeleteSymbolicLink(
IN PUNICODE_STRING DosName
);
NTSTATUS
QuerySuggestedLinkName(
IN PUNICODE_STRING SymbolicName,
OUT PUNICODE_STRING SuggestedLinkName,
OUT PBOOLEAN UseOnlyIfThereAreNoOtherLinks
);
NTSTATUS
QuerySymbolicLinkNamesFromStorage(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_INFORMATION DeviceInformation,
IN PUNICODE_STRING SuggestedLinkName,
IN BOOLEAN UseOnlyIfThereAreNoOtherLinks,
OUT PUNICODE_STRING * SymLinks,
OUT PULONG SymLinkCount,
IN BOOLEAN HasGuid,
IN LPGUID Guid
);
PSAVED_LINK_INFORMATION
RemoveSavedLinks(
IN PDEVICE_EXTENSION DeviceExtension,
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
BOOLEAN
RedirectSavedLink(
IN PSAVED_LINK_INFORMATION SavedLinkInformation,
IN PUNICODE_STRING DosName,
IN PUNICODE_STRING NewLink
);
VOID
SendLinkCreated(
IN PUNICODE_STRING SymbolicName
);
NTSTATUS
CreateNewVolumeName(
OUT PUNICODE_STRING VolumeName,
IN PGUID VolumeGuid OPTIONAL
);
BOOLEAN
IsDriveLetter(
PUNICODE_STRING SymbolicName
);
VOID
DeleteSymbolicLinkNameFromMemory(
IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicLink,
IN BOOLEAN MarkOffline
);
#endif /* _MNTMGR_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
<module name="mountmgr" type="kernelmodedriver" installbase="system32/drivers" installname="mountmgr.sys">
<bootstrap installbase="$(CDOUTPUT)" />
<define name="NTDDI_VERSION">0x05020400</define>
<include base="mountmgr">.</include>
<library>ntoskrnl</library>
<library>hal</library>
<library>ioevent</library>
<library>wdmguid</library>
<file>database.c</file>
<file>device.c</file>
<file>mountmgr.c</file>
<file>notify.c</file>
<file>point.c</file>
<file>symlink.c</file>
<file>uniqueid.c</file>
<file>mountmgr.rc</file>
<pch>mntmgr.h</pch>
</module>

View file

@ -0,0 +1,6 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Mount Point Manager\0"
#define REACTOS_STR_INTERNAL_NAME "mountmgr.sys\0"
#define REACTOS_STR_ORIGINAL_FILENAME "mountmgr.sys\0"
#include <reactos/version.rc>

View file

@ -0,0 +1,757 @@
/*
* 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/notify.c
* PURPOSE: Mount Manager - Notifications handlers
* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
* Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include "mntmgr.h"
#define NDEBUG
#include <debug.h>
/*
* @implemented
*/
VOID
SendOnlineNotification(IN PUNICODE_STRING SymbolicName)
{
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK IoStatusBlock;
/* Get device object */
Status = IoGetDeviceObjectPointer(SymbolicName,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
return;
}
/* And attached device object */
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
/* And send VOLUME_ONLINE */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_ONLINE,
DeviceObject,
NULL, 0,
NULL, 0,
FALSE,
&Event,
&IoStatusBlock);
if (!Irp)
{
goto Cleanup;
}
Stack = IoGetNextIrpStackLocation(Irp);
Stack->FileObject = FileObject;
Status = IofCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
Cleanup:
ObfDereferenceObject(DeviceObject);
ObfDereferenceObject(FileObject);
return;
}
/*
* @implemented
*/
VOID
NTAPI
SendOnlineNotificationWorker(IN PVOID Parameter)
{
KIRQL OldIrql;
PLIST_ENTRY Head;
PDEVICE_EXTENSION DeviceExtension;
PONLINE_NOTIFICATION_WORK_ITEM WorkItem;
PONLINE_NOTIFICATION_WORK_ITEM NewWorkItem;
WorkItem = (PONLINE_NOTIFICATION_WORK_ITEM)Parameter;
DeviceExtension = WorkItem->DeviceExtension;
/* First, send the notification */
SendOnlineNotification(&(WorkItem->SymbolicName));
OldIrql = KfAcquireSpinLock(&(DeviceExtension->WorkerLock));
/* If there are no notifications running any longer, reset event */
if (--DeviceExtension->OnlineNotificationCount == 0)
{
KeSetEvent(&(DeviceExtension->OnlineNotificationEvent), 0, FALSE);
}
/* If there are still notifications in queue */
if (!IsListEmpty(&(DeviceExtension->OnlineNotificationListHead)))
{
/* Queue a new one for execution */
Head = RemoveHeadList(&(DeviceExtension->OnlineNotificationListHead));
NewWorkItem = CONTAINING_RECORD(Head, ONLINE_NOTIFICATION_WORK_ITEM, List);
KfReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
NewWorkItem->List.Blink = NULL;
NewWorkItem->List.Flink = NULL;
ExQueueWorkItem((PWORK_QUEUE_ITEM)NewWorkItem, DelayedWorkQueue);
}
else
{
/* Mark it's over */
DeviceExtension->OnlineNotificationWorkerActive = 0;
KfReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
}
FreePool(WorkItem->SymbolicName.Buffer);
FreePool(WorkItem);
return;
}
/*
* @implemented
*/
VOID
PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName)
{
KIRQL OldIrql;
PONLINE_NOTIFICATION_WORK_ITEM WorkItem;
/* Allocate a notification work item */
WorkItem = AllocatePool(sizeof(ONLINE_NOTIFICATION_WORK_ITEM));
if (!WorkItem)
{
return;
}
WorkItem->List.Flink = NULL;
WorkItem->DeviceExtension = DeviceExtension;
WorkItem->WorkerRoutine = SendOnlineNotificationWorker;
WorkItem->Parameter = WorkItem;
WorkItem->SymbolicName.Length = SymbolicName->Length;
WorkItem->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(WCHAR);
WorkItem->SymbolicName.Buffer = AllocatePool(WorkItem->SymbolicName.MaximumLength);
if (!WorkItem->SymbolicName.Buffer)
{
FreePool(WorkItem);
return;
}
RtlCopyMemory(WorkItem->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
WorkItem->SymbolicName.Buffer[SymbolicName->Length / sizeof(WCHAR)] = UNICODE_NULL;
OldIrql = KfAcquireSpinLock(&(DeviceExtension->WorkerLock));
DeviceExtension->OnlineNotificationCount++;
/* If no worker are active */
if (DeviceExtension->OnlineNotificationWorkerActive == 0)
{
/* Queue that one for execution */
DeviceExtension->OnlineNotificationWorkerActive == 1;
ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
}
else
{
/* Otherwise, just put it in the queue list */
InsertTailList(&(DeviceExtension->OnlineNotificationListHead), &(WorkItem->List));
}
KfReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
return;
}
/*
* @implemented
*/
VOID
WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension)
{
KIRQL OldIrql;
KeInitializeEvent(&(DeviceExtension->OnlineNotificationEvent), NotificationEvent, FALSE);
OldIrql = KfAcquireSpinLock(&(DeviceExtension->WorkerLock));
/* Just wait all the worker are done */
if (DeviceExtension->OnlineNotificationCount != 1)
{
DeviceExtension->OnlineNotificationCount--;
KfReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
KeWaitForSingleObject(&(DeviceExtension->OnlineNotificationEvent),
Executive,
KernelMode,
FALSE,
NULL);
OldIrql = KfAcquireSpinLock(&(DeviceExtension->WorkerLock));
DeviceExtension->OnlineNotificationCount++;
}
KfReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
MountMgrTargetDeviceNotification(IN PVOID NotificationStructure,
IN PVOID Context)
{
PDEVICE_EXTENSION DeviceExtension;
PDEVICE_INFORMATION DeviceInformation;
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
DeviceInformation = Context;
DeviceExtension = DeviceInformation->DeviceExtension;
Notification = NotificationStructure;
/* If it's to signal that removal is complete, then, execute the function */
if (IsEqualGUID(&(Notification->Event), &GUID_TARGET_DEVICE_REMOVE_COMPLETE))
{
MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
}
/* It it's to signal that a volume has been mounted
* Verify if a database sync is required and execute it
*/
else if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT))
{
if (InterlockedCompareExchange(&(DeviceInformation->MountState),
FALSE,
TRUE) == TRUE)
{
InterlockedDecrement(&(DeviceInformation->MountState));
}
else
{
if (DeviceInformation->NeedsReconcile)
{
DeviceInformation->NeedsReconcile = FALSE;
ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
}
}
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
RegisterForTargetDeviceNotification(IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_INFORMATION DeviceInformation)
{
NTSTATUS Status;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
/* Get device object */
Status = IoGetDeviceObjectPointer(&(DeviceInformation->DeviceName),
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
return;
}
/* And simply register for notifications */
Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange,
0, FileObject,
DeviceExtension->DriverObject,
MountMgrTargetDeviceNotification,
DeviceInformation,
&(DeviceInformation->TargetDeviceNotificationEntry));
if (!NT_SUCCESS(Status))
{
DeviceInformation->TargetDeviceNotificationEntry = NULL;
}
ObfDereferenceObject(FileObject);
return;
}
/*
* @implemented
*/
VOID
MountMgrNotify(IN PDEVICE_EXTENSION DeviceExtension)
{
PIRP Irp;
KIRQL OldIrql;
LIST_ENTRY CopyList;
PLIST_ENTRY NextEntry;
/* Increase the epic number */
DeviceExtension->EpicNumber++;
InitializeListHead(&CopyList);
/* Copy all the pending IRPs for notification */
IoAcquireCancelSpinLock(&OldIrql);
while (!IsListEmpty(&(DeviceExtension->IrpListHead)))
{
NextEntry = RemoveHeadList(&(DeviceExtension->IrpListHead));
Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
InsertTailList(&CopyList, &(Irp->Tail.Overlay.ListEntry));
}
IoReleaseCancelSpinLock(OldIrql);
/* Then, notifiy them one by one */
while (!IsListEmpty(&CopyList))
{
NextEntry = RemoveHeadList(&CopyList);
Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->EpicNumber;
Irp->IoStatus.Information = sizeof(DeviceExtension->EpicNumber);
IofCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
/*
* @implemented
*/
VOID
MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING DeviceName,
IN BOOLEAN ValidateVolume)
{
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
PLIST_ENTRY NextEntry;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK IoStatusBlock;
PDEVICE_RELATIONS DeviceRelations;
PDEVICE_INFORMATION DeviceInformation;
TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification;
/* If we have to validate volume */
if (ValidateVolume)
{
/* Then, ensure we can find the device */
NextEntry = DeviceExtension->DeviceListHead.Flink;
while (NextEntry != &(DeviceExtension->DeviceListHead))
{
DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
{
break;
}
}
if (NextEntry == &(DeviceExtension->DeviceListHead) ||
!DeviceInformation->Volume)
{
return;
}
}
/* Then, get device object */
Status = IoGetDeviceObjectPointer(DeviceName,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
return;
}
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Set up empty IRP (yes, yes!) */
Irp = IoBuildDeviceIoControlRequest(0,
DeviceObject,
NULL,
0,
NULL,
0,
FALSE,
&Event,
&IoStatusBlock);
if (!Irp)
{
ObfDereferenceObject(DeviceObject);
ObfDereferenceObject(FileObject);
}
Stack = IoGetNextIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Information = 0;
/* Properly set it, we want to query device relations */
Stack->MajorFunction = IRP_MJ_PNP;
Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
Stack->FileObject = FileObject;
/* And call driver */
Status = IofCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
ObfDereferenceObject(DeviceObject);
ObfDereferenceObject(FileObject);
if (!NT_SUCCESS(Status))
{
return;
}
/* Validate device return */
DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
if (DeviceRelations->Count < 1)
{
ExFreePool(DeviceRelations);
return;
}
DeviceObject = DeviceRelations->Objects[0];
ExFreePool(DeviceRelations);
/* Set up real notification */
DeviceNotification.Version = 1;
DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE;
DeviceNotification.FileObject = NULL;
DeviceNotification.NameBufferOffset = -1;
/* And report */
IoReportTargetDeviceChangeAsynchronous(DeviceObject,
&DeviceNotification,
NULL, NULL);
ObfDereferenceObject(DeviceObject);
return;
}
/*
* @implemented
*/
VOID
RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem)
{
PDEVICE_EXTENSION DeviceExtension;
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
/* If even if being worked, it's too late */
if (WorkItem->Event)
{
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
KeSetEvent(WorkItem->Event, 0, FALSE);
}
else
{
/* Otherwise, remove it from the list, and delete it */
RemoveEntryList(&(WorkItem->UniqueIdWorkerItemListEntry));
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
IoFreeIrp(WorkItem->Irp);
FreePool(WorkItem->DeviceName.Buffer);
FreePool(WorkItem->IrpBuffer);
FreePool(WorkItem);
}
}
/*
* @implemented
*/
VOID
NTAPI
UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
PUNIQUE_ID_WORK_ITEM WorkItem = Context;
PMOUNTDEV_UNIQUE_ID OldUniqueId, NewUniqueId;
PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange;
/* Validate worker */
if (!NT_SUCCESS(WorkItem->Irp->IoStatus.Status))
{
RemoveWorkItem(WorkItem);
return;
}
UniqueIdChange = WorkItem->Irp->AssociatedIrp.SystemBuffer;
/* Get the old unique ID */
OldUniqueId = AllocatePool(UniqueIdChange->OldUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!OldUniqueId)
{
RemoveWorkItem(WorkItem);
return;
}
OldUniqueId->UniqueIdLength = UniqueIdChange->OldUniqueIdLength;
RtlCopyMemory(OldUniqueId->UniqueId,
(PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->OldUniqueIdOffset),
UniqueIdChange->OldUniqueIdLength);
/* Get the new unique ID */
NewUniqueId = AllocatePool(UniqueIdChange->NewUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!NewUniqueId)
{
FreePool(OldUniqueId);
RemoveWorkItem(WorkItem);
return;
}
NewUniqueId->UniqueIdLength = UniqueIdChange->NewUniqueIdLength;
RtlCopyMemory(NewUniqueId->UniqueId,
(PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->NewUniqueIdOffset),
UniqueIdChange->NewUniqueIdLength);
/* Call the real worker */
MountMgrUniqueIdChangeRoutine(WorkItem->DeviceExtension, OldUniqueId, NewUniqueId);
IssueUniqueIdChangeNotifyWorker(WorkItem, NewUniqueId);
FreePool(NewUniqueId);
FreePool(OldUniqueId);
return;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PUNIQUE_ID_WORK_ITEM WorkItem = Context;
/* Simply queue the work item */
IoQueueWorkItem(WorkItem->WorkItem,
UniqueIdChangeNotifyWorker,
DelayedWorkQueue,
WorkItem);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*
* @implemented
*/
VOID
IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem,
IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
PIRP Irp;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION Stack;
PDEVICE_OBJECT DeviceObject;
/* Get the device object */
Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName),
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
RemoveWorkItem(WorkItem);
return;
}
/* And then, the attached device */
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
/* Initialize the IRP */
Irp = WorkItem->Irp;
IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), WorkItem->StackSize);
if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0)
{
ObfDereferenceObject(FileObject);
ObfDereferenceObject(DeviceObject);
RemoveWorkItem(WorkItem);
return;
}
Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT));
Stack = IoGetNextIrpStackLocation(Irp);
Stack->Parameters.DeviceIoControl.InputBufferLength = UniqueId->UniqueIdLength + sizeof(USHORT);
Stack->Parameters.DeviceIoControl.OutputBufferLength = WorkItem->IrpBufferLength;
Stack->Parameters.DeviceIoControl.Type3InputBuffer = 0;
Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY;
Stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject,
Irp,
UniqueIdChangeNotifyCompletion,
WorkItem,
TRUE, TRUE, TRUE);
if (!NT_SUCCESS(Status))
{
ObfDereferenceObject(FileObject);
ObfDereferenceObject(DeviceObject);
RemoveWorkItem(WorkItem);
return;
}
/* Call the driver */
IofCallDriver(DeviceObject, Irp);
ObfDereferenceObject(FileObject);
ObfDereferenceObject(DeviceObject);
}
/*
* @implemented
*/
VOID
IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING DeviceName,
IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
NTSTATUS Status;
PVOID IrpBuffer = NULL;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PUNIQUE_ID_WORK_ITEM WorkItem = NULL;
/* Get the associated device object */
Status = IoGetDeviceObjectPointer(DeviceName,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
return;
}
/* And then, get attached device */
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
ObfDereferenceObject(FileObject);
/* Allocate a work item */
WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM));
if (!WorkItem)
{
ObfDereferenceObject(DeviceObject);
return;
}
WorkItem->Event = NULL;
WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
if (!WorkItem->WorkItem)
{
ObfDereferenceObject(DeviceObject);
goto Cleanup;
}
WorkItem->DeviceExtension = DeviceExtension;
WorkItem->StackSize = DeviceObject->StackSize;
/* Already provide the IRP */
WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
ObfDereferenceObject(DeviceObject);
if (!WorkItem->Irp)
{
goto Cleanup;
}
/* Ensure it has enough space */
IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024);
if (!IrpBuffer)
{
goto Cleanup;
}
WorkItem->DeviceName.Length = DeviceName->Length;
WorkItem->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR);
WorkItem->DeviceName.Buffer = AllocatePool(WorkItem->DeviceName.MaximumLength);
if (!WorkItem->DeviceName.Buffer)
{
goto Cleanup;
}
RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
WorkItem->IrpBuffer = IrpBuffer;
WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024;
/* Add the worker in the list */
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
InsertHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead), &(WorkItem->UniqueIdWorkerItemListEntry));
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
/* And call the worker */
IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId);
return;
Cleanup:
if (IrpBuffer)
{
FreePool(IrpBuffer);
}
if (WorkItem->Irp)
{
IoFreeIrp(WorkItem->Irp);
}
if (WorkItem->WorkItem)
{
IoFreeWorkItem(WorkItem->WorkItem);
}
if (WorkItem)
{
FreePool(WorkItem);
}
}

View file

@ -0,0 +1,572 @@
/*
* ReactOS kernel
* Copyright (C) 2011-2012 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/point.c
* PURPOSE: Mount Manager - Mount points
* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include "mntmgr.h"
#define NDEBUG
#include <debug.h>
/*
* @implemented
*/
NTSTATUS
MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName)
{
NTSTATUS Status;
PLIST_ENTRY DeviceEntry;
PMOUNTDEV_UNIQUE_ID UniqueId;
PSYMLINK_INFORMATION SymlinkInformation;
UNICODE_STRING SymLink, TargetDeviceName;
PDEVICE_INFORMATION DeviceInformation, DeviceInfo;
/* Get device name */
Status = QueryDeviceInformation(SymbolicLinkName,
&TargetDeviceName,
NULL, NULL, NULL,
NULL, NULL, NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* First of all, try to find device */
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
if (RtlCompareUnicodeString(&TargetDeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
{
break;
}
}
/* Copy symbolic link name and null terminate it */
SymLink.Buffer = AllocatePool(SymbolicLinkName->Length + sizeof(UNICODE_NULL));
if (!SymLink.Buffer)
{
FreePool(TargetDeviceName.Buffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(SymLink.Buffer, SymbolicLinkName->Buffer, SymbolicLinkName->Length);
SymLink.Buffer[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
SymLink.Length = SymbolicLinkName->Length;
SymLink.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL);
/* If we didn't find device */
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
{
/* Then, try with unique ID */
Status = QueryDeviceInformation(SymbolicLinkName,
NULL, &UniqueId,
NULL, NULL, NULL,
NULL, NULL);
if (!NT_SUCCESS(Status))
{
FreePool(TargetDeviceName.Buffer);
FreePool(SymLink.Buffer);
return Status;
}
/* Create a link to the device */
Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
if (!NT_SUCCESS(Status))
{
FreePool(UniqueId);
FreePool(TargetDeviceName.Buffer);
FreePool(SymLink.Buffer);
return Status;
}
/* If caller provided driver letter, delete it */
if (IsDriveLetter(&SymLink))
{
DeleteRegistryDriveLetter(UniqueId);
}
/* Device will be identified with its unique ID */
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
SymLink.Buffer,
REG_BINARY,
UniqueId->UniqueId,
UniqueId->UniqueIdLength);
FreePool(UniqueId);
FreePool(TargetDeviceName.Buffer);
FreePool(SymLink.Buffer);
return Status;
}
/* If call provided a driver letter whereas device already has one
* fail, this is not doable
*/
if (IsDriveLetter(&SymLink) && HasDriveLetter(DeviceInformation))
{
FreePool(TargetDeviceName.Buffer);
FreePool(SymLink.Buffer);
return STATUS_INVALID_PARAMETER;
}
/* Now, create a link */
Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
FreePool(TargetDeviceName.Buffer);
if (!NT_SUCCESS(Status))
{
FreePool(SymLink.Buffer);
return Status;
}
/* Associate Unique ID <-> symbolic name */
UniqueId = DeviceInformation->UniqueId;
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
SymLink.Buffer,
REG_BINARY,
UniqueId->UniqueId,
UniqueId->UniqueIdLength);
if (!NT_SUCCESS(Status))
{
GlobalDeleteSymbolicLink(&SymLink);
FreePool(SymLink.Buffer);
return Status;
}
/* Now, prepare to save the link with the device */
SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
if (!SymlinkInformation)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
GlobalDeleteSymbolicLink(&SymLink);
FreePool(SymLink.Buffer);
return Status;
}
SymlinkInformation->Name.Length = SymLink.Length;
SymlinkInformation->Name.MaximumLength = SymLink.Length + sizeof(UNICODE_NULL);
SymlinkInformation->Name.Buffer = AllocatePool(SymlinkInformation->Name.MaximumLength);
if (!SymlinkInformation->Name.Buffer)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
FreePool(SymlinkInformation);
GlobalDeleteSymbolicLink(&SymLink);
FreePool(SymLink.Buffer);
return Status;
}
/* Save the link and mark it online */
RtlCopyMemory(SymlinkInformation->Name.Buffer, SymLink.Buffer, SymlinkInformation->Name.Length);
SymlinkInformation->Name.Buffer[SymlinkInformation->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
SymlinkInformation->Online = TRUE;
InsertTailList(&DeviceInformation->SymbolicLinksListHead, &SymlinkInformation->SymbolicLinksListEntry);
SendLinkCreated(&(SymlinkInformation->Name));
/* If we have a drive letter */
if (IsDriveLetter(&SymLink))
{
/* Then, delete the no drive letter entry */
DeleteNoDriveLetterEntry(UniqueId);
/* And post online notification if asked */
if (!DeviceInformation->SkipNotifications)
{
PostOnlineNotification(DeviceExtension, &DeviceInformation->SymbolicName);
}
}
/* If that's a volume with automatic drive letter, it's now time to resync databases */
if (MOUNTMGR_IS_VOLUME_NAME(&SymLink) && DeviceExtension->AutomaticDriveLetter)
{
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInfo = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
/* If there's one, ofc! */
if (!DeviceInfo->NoDatabase)
{
ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInfo);
}
}
}
/* Notify & quit */
FreePool(SymLink.Buffer);
MountMgrNotify(DeviceExtension);
if (!DeviceInformation->Volume)
{
MountMgrNotifyNameChange(DeviceExtension, DeviceName, FALSE);
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
QueryPointsFromMemory(IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL,
IN PUNICODE_STRING SymbolicName OPTIONAL)
{
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
UNICODE_STRING DeviceName;
ULONG TotalSize, TotalSymLinks;
PMOUNTMGR_MOUNT_POINTS MountPoints;
PDEVICE_INFORMATION DeviceInformation;
PLIST_ENTRY DeviceEntry, SymlinksEntry;
PSYMLINK_INFORMATION SymlinkInformation;
/* If we got a symbolic link, query device */
if (SymbolicName)
{
Status = QueryDeviceInformation(SymbolicName,
&DeviceName,
NULL, NULL,
NULL, NULL,
NULL, NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
/* Browse all the links to count number of links & size used */
TotalSize = 0;
TotalSymLinks = 0;
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
/* If we were given an unique ID, it has to match */
if (UniqueId)
{
if (UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
{
continue;
}
if (RtlCompareMemory(UniqueId->UniqueId,
DeviceInformation->UniqueId->UniqueId,
UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
{
continue;
}
}
/* Or, if we had a symlink, it has to match */
else if (SymbolicName)
{
if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
{
continue;
}
}
/* Once here, it matched, save device name & unique ID size */
TotalSize += DeviceInformation->DeviceName.Length + DeviceInformation->UniqueId->UniqueIdLength;
/* And count number of symlinks (and their size) */
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
SymlinksEntry = SymlinksEntry->Flink)
{
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
TotalSize += SymlinkInformation->Name.Length;
TotalSymLinks++;
}
/* We had a specific item to find
* if we reach that point, we found it, no need to continue
*/
if (UniqueId || SymbolicName)
{
break;
}
}
/* If we were looking for specific item, ensure we found it */
if (UniqueId || SymbolicName)
{
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
{
if (DeviceName.Buffer)
{
FreePool(DeviceName.Buffer);
}
return STATUS_INVALID_PARAMETER;
}
}
/* Now, ensure output buffer can hold everything */
Stack = IoGetNextIrpStackLocation(Irp);
MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
/* Ensure we set output to let user reallocate! */
MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalSize;
MountPoints->NumberOfMountPoints = TotalSymLinks;
if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
{
return STATUS_BUFFER_OVERFLOW;
}
/* Now, start putting mount points */
TotalSymLinks = 0;
TotalSize = 0;
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
/* Find back correct mount point */
if (UniqueId)
{
if (!UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
{
continue;
}
if (RtlCompareMemory(UniqueId->UniqueId,
DeviceInformation->UniqueId->UniqueId,
UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
{
continue;
}
}
else if (SymbolicName)
{
if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
{
continue;
}
}
/* Now we've got it, but all the data */
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
SymlinksEntry = SymlinksEntry->Flink)
{
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
TotalSize;
MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
SymlinkInformation->Name.Length +
TotalSize;
MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
SymlinkInformation->Name.Length +
DeviceInformation->UniqueId->UniqueIdLength +
TotalSize;
MountPoints->MountPoints[TotalSymLinks].DeviceNameLength = DeviceInformation->DeviceName.Length;
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset),
SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset),
DeviceInformation->UniqueId->UniqueId, DeviceInformation->UniqueId->UniqueIdLength);
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset),
DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
/* Update counters */
TotalSymLinks++;
TotalSize += SymlinkInformation->Name.Length + DeviceInformation->UniqueId->UniqueIdLength +
DeviceInformation->DeviceName.Length;
}
if (UniqueId || SymbolicName)
{
break;
}
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
IN PIRP Irp)
{
NTSTATUS Status;
ULONG TotalLength;
PIO_STACK_LOCATION Stack;
UNICODE_STRING DeviceName;
PMOUNTMGR_MOUNT_POINTS MountPoints;
PDEVICE_INFORMATION DeviceInformation;
PLIST_ENTRY DeviceEntry, SymlinksEntry;
PSYMLINK_INFORMATION SymlinkInformation;
/* Find device */
Status = QueryDeviceInformation(SymbolicName, &DeviceName,
NULL, NULL, NULL,
NULL, NULL, NULL);
if (NT_SUCCESS(Status))
{
/* Look for the device information */
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
if (RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
{
break;
}
}
FreePool(DeviceName.Buffer);
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
{
return STATUS_INVALID_PARAMETER;
}
/* Check for the link */
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
SymlinksEntry = DeviceEntry->Flink)
{
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE) == 0)
{
break;
}
}
if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
{
return STATUS_INVALID_PARAMETER;
}
}
else
{
/* Browse all the devices to try to find the one
* that has the given link...
*/
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
DeviceEntry != &(DeviceExtension->DeviceListHead);
DeviceEntry = DeviceEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
SymlinksEntry = SymlinksEntry->Flink)
{
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE) == 0)
{
break;
}
}
if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
{
break;
}
}
/* Even that way we didn't find, give up! */
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
}
/* Get output buffer */
Stack = IoGetNextIrpStackLocation(Irp);
MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
/* Compute output length */
TotalLength = DeviceInformation->UniqueId->UniqueIdLength +
SymlinkInformation->Name.Length + DeviceInformation->DeviceName.Length;
/* Give length to allow reallocation */
MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalLength;
MountPoints->NumberOfMountPoints = 1;
if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
{
return STATUS_BUFFER_OVERFLOW;
}
/* Write out data */
MountPoints->MountPoints[0].SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS);
MountPoints->MountPoints[0].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
/* If link is online write it's unique ID, otherwise, forget about it */
if (SymlinkInformation->Online)
{
MountPoints->MountPoints[0].UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
SymlinkInformation->Name.Length;
MountPoints->MountPoints[0].UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
}
else
{
MountPoints->MountPoints[0].UniqueIdOffset = 0;
MountPoints->MountPoints[0].UniqueIdLength = 0;
}
MountPoints->MountPoints[0].DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
SymlinkInformation->Name.Length +
DeviceInformation->UniqueId->UniqueIdLength;
MountPoints->MountPoints[0].DeviceNameLength = DeviceInformation->DeviceName.Length;
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].SymbolicLinkNameOffset),
SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
if (SymlinkInformation->Online)
{
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].UniqueIdOffset),
DeviceInformation->UniqueId->UniqueId, DeviceInformation->UniqueId->UniqueIdLength);
}
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].DeviceNameOffset),
DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
return STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,436 @@
/*
* 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/uniqueid.c
* PURPOSE: Mount Manager - Unique ID
* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include "mntmgr.h"
#define NDEBUG
#include <debug.h>
/*
* @implemented
*/
NTSTATUS
NTAPI
ChangeUniqueIdRoutine(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PMOUNTDEV_UNIQUE_ID OldUniqueId = Context;
PMOUNTDEV_UNIQUE_ID NewUniqueId = EntryContext;
/* Validate parameters not to corrupt registry */
if ((ValueType != REG_BINARY) ||
(OldUniqueId->UniqueIdLength != ValueLength))
{
return STATUS_SUCCESS;
}
if (RtlCompareMemory(OldUniqueId->UniqueId, ValueData, ValueLength) == ValueLength)
{
/* Write new data */
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
ValueName,
REG_BINARY,
NewUniqueId,
NewUniqueId->UniqueIdLength);
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
MountMgrUniqueIdChangeRoutine(IN PDEVICE_EXTENSION DeviceExtension,
IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
{
NTSTATUS Status;
BOOLEAN ResyncNeeded;
PUNIQUE_ID_REPLICATE DuplicateId;
PDEVICE_INFORMATION DeviceInformation;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
PMOUNTDEV_UNIQUE_ID UniqueId, NewDuplicateId;
PLIST_ENTRY ListHead, NextEntry, ReplicatedHead, NextReplicated;
/* Synchronise with remote databases */
Status = WaitForRemoteDatabaseSemaphore(DeviceExtension);
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].QueryRoutine = ChangeUniqueIdRoutine;
QueryTable[0].EntryContext = NewUniqueId;
/* Write new data */
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
QueryTable,
OldUniqueId,
NULL);
/* Browse all the devices to find the one that
* owns the old unique ID
*/
ListHead = &(DeviceExtension->DeviceListHead);
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
DeviceInformation = CONTAINING_RECORD(NextEntry,
DEVICE_INFORMATION,
DeviceListEntry);
if (DeviceInformation->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength &&
RtlCompareMemory(OldUniqueId->UniqueId,
DeviceInformation->UniqueId->UniqueId,
OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength)
{
break;
}
NextEntry = NextEntry->Flink;
}
/* If we didn't find any release everything and quit */
if (ListHead == NextEntry)
{
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
1, FALSE);
if (NT_SUCCESS(Status))
{
ReleaseRemoteDatabaseSemaphore(DeviceExtension);
}
return;
}
/* If lock failed, then, just update this database */
if (!NT_SUCCESS(Status))
{
ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
1, FALSE);
return;
}
/* Allocate new unique ID */
UniqueId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!UniqueId)
{
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
1, FALSE);
ReleaseRemoteDatabaseSemaphore(DeviceExtension);
return;
}
/* Release old one */
FreePool(DeviceInformation->UniqueId);
/* And set new one */
DeviceInformation->UniqueId = UniqueId;
UniqueId->UniqueIdLength = NewUniqueId->UniqueIdLength;
RtlCopyMemory(UniqueId->UniqueId, NewUniqueId->UniqueId, NewUniqueId->UniqueIdLength);
/* Now, check if it's required to update replicated unique IDs as well */
ListHead = &(DeviceExtension->DeviceListHead);
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
DeviceInformation = CONTAINING_RECORD(NextEntry,
DEVICE_INFORMATION,
DeviceListEntry);
ResyncNeeded = FALSE;
ReplicatedHead = &(DeviceInformation->ReplicatedUniqueIdsListHead);
NextReplicated = ReplicatedHead->Flink;
while (ReplicatedHead != NextReplicated)
{
DuplicateId = CONTAINING_RECORD(NextReplicated,
UNIQUE_ID_REPLICATE,
ReplicatedUniqueIdsListEntry);
if (DuplicateId->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength)
{
if (RtlCompareMemory(DuplicateId->UniqueId->UniqueId,
OldUniqueId->UniqueId,
OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength)
{
/* It was our old unique ID */
NewDuplicateId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (NewDuplicateId)
{
/* Update it */
ResyncNeeded = TRUE;
FreePool(DuplicateId->UniqueId);
DuplicateId->UniqueId = NewDuplicateId;
DuplicateId->UniqueId->UniqueIdLength = NewUniqueId->UniqueIdLength;
RtlCopyMemory(NewDuplicateId->UniqueId, NewUniqueId->UniqueId, NewUniqueId->UniqueIdLength);
}
}
}
NextReplicated = NextReplicated->Flink;
}
/* If resync is required on this device, do it */
if (ResyncNeeded)
{
ChangeRemoteDatabaseUniqueId(DeviceInformation, OldUniqueId, NewUniqueId);
}
NextEntry = NextEntry->Flink;
}
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
ReleaseRemoteDatabaseSemaphore(DeviceExtension);
return;
}
/*
* @implemented
*/
BOOLEAN
IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension,
IN PDATABASE_ENTRY DatabaseEntry)
{
PLIST_ENTRY NextEntry;
PDEVICE_INFORMATION DeviceInformation;
/* If no device, no unique ID (O'rly?!)
* ./)/).
* (°-°)
* (___) ORLY?
* " "
*/
if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
{
return FALSE;
}
/* Now we know that we have devices, find the one */
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
NextEntry != &(DeviceExtension->DeviceListHead);
NextEntry = NextEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(NextEntry,
DEVICE_INFORMATION,
DeviceListEntry);
if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
{
continue;
}
/* It's matching! */
if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DeviceInformation->UniqueId->UniqueId,
DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
{
return TRUE;
}
}
/* No luck... */
return FALSE;
}
/*
* @implemented
*/
VOID
CreateNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
UUID Guid;
PWCHAR String;
UNICODE_STRING GuidString;
/* Entry with no drive letter are made that way:
* Instead of having a path with the letter,
* you have GUID with the unique ID.
*/
if (!NT_SUCCESS(ExUuidCreate(&Guid)))
{
return;
}
/* Convert to string */
if (!NT_SUCCESS(RtlStringFromGUID(&Guid, &GuidString)))
{
return;
}
/* No letter entries must start with #, so allocate a proper string */
String = AllocatePool(GuidString.Length + 2 * sizeof(WCHAR));
if (!String)
{
ExFreePoolWithTag(GuidString.Buffer, 0);
return;
}
/* Write the complete string */
String[0] = L'#';
RtlCopyMemory(String + 1, GuidString.Buffer, GuidString.Length);
String[GuidString.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Don't need that one anymore */
ExFreePoolWithTag(GuidString.Buffer, 0);
/* Write the entry */
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
String,
REG_BINARY,
UniqueId->UniqueId,
UniqueId->UniqueIdLength);
FreePool(String);
return;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
CheckForNoDriveLetterEntry(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PBOOLEAN EntryPresent = EntryContext;
PMOUNTDEV_UNIQUE_ID UniqueId = Context;
/* Check if matches no drive letter entry */
if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
UniqueId->UniqueIdLength != ValueLength)
{
return STATUS_SUCCESS;
}
/* Compare unique ID */
if (RtlCompareMemory(UniqueId->UniqueId, ValueData, ValueLength) == ValueLength)
{
*EntryPresent = TRUE;
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN
HasNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
BOOLEAN EntryPresent = FALSE;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].QueryRoutine = CheckForNoDriveLetterEntry;
QueryTable[0].EntryContext = &EntryPresent;
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
QueryTable,
UniqueId,
NULL);
return EntryPresent;
}
/*
* @implemented
*/
VOID
UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation, IN PDATABASE_ENTRY DatabaseEntry)
{
PLIST_ENTRY NextEntry;
PUNIQUE_ID_REPLICATE ReplicatedUniqueId, NewEntry;
/* Browse all the device replicated unique IDs */
for (NextEntry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink;
NextEntry != &(DeviceInformation->ReplicatedUniqueIdsListHead);
NextEntry = NextEntry->Flink)
{
ReplicatedUniqueId = CONTAINING_RECORD(NextEntry,
UNIQUE_ID_REPLICATE,
ReplicatedUniqueIdsListEntry);
if (ReplicatedUniqueId->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
{
continue;
}
/* If we find the UniqueId to update, break */
if (RtlCompareMemory(ReplicatedUniqueId->UniqueId->UniqueId,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
ReplicatedUniqueId->UniqueId->UniqueIdLength) == ReplicatedUniqueId->UniqueId->UniqueIdLength)
{
break;
}
}
/* We found the unique ID, no need to continue */
if (NextEntry != &(DeviceInformation->ReplicatedUniqueIdsListHead))
{
return;
}
/* Allocate a new entry for unique ID */
NewEntry = AllocatePool(sizeof(UNIQUE_ID_REPLICATE));
if (!NewEntry)
{
return;
}
/* Allocate the unique ID */
NewEntry->UniqueId = AllocatePool(DatabaseEntry->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!NewEntry->UniqueId)
{
FreePool(NewEntry);
return;
}
/* Copy */
NewEntry->UniqueId->UniqueIdLength = DatabaseEntry->UniqueIdLength;
RtlCopyMemory(NewEntry->UniqueId->UniqueId,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DatabaseEntry->UniqueIdLength);
/* And insert into replicated unique IDs list */
InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &NewEntry->ReplicatedUniqueIdsListEntry);
return;
}