mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[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:
parent
2f5db208de
commit
31572e7770
15 changed files with 8258 additions and 0 deletions
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
2
drivers/filters/CMakeLists.txt
Normal file
2
drivers/filters/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
add_subdirectory(mountmgr)
|
7
drivers/filters/directory.rbuild
Normal file
7
drivers/filters/directory.rbuild
Normal 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>
|
21
drivers/filters/mountmgr/CMakeLists.txt
Normal file
21
drivers/filters/mountmgr/CMakeLists.txt
Normal 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)
|
1480
drivers/filters/mountmgr/database.c
Normal file
1480
drivers/filters/mountmgr/database.c
Normal file
File diff suppressed because it is too large
Load diff
1601
drivers/filters/mountmgr/device.c
Normal file
1601
drivers/filters/mountmgr/device.c
Normal file
File diff suppressed because it is too large
Load diff
452
drivers/filters/mountmgr/mntmgr.h
Normal file
452
drivers/filters/mountmgr/mntmgr.h
Normal 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_ */
|
1896
drivers/filters/mountmgr/mountmgr.c
Normal file
1896
drivers/filters/mountmgr/mountmgr.c
Normal file
File diff suppressed because it is too large
Load diff
20
drivers/filters/mountmgr/mountmgr.rbuild
Normal file
20
drivers/filters/mountmgr/mountmgr.rbuild
Normal 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>
|
6
drivers/filters/mountmgr/mountmgr.rc
Normal file
6
drivers/filters/mountmgr/mountmgr.rc
Normal 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>
|
757
drivers/filters/mountmgr/notify.c
Normal file
757
drivers/filters/mountmgr/notify.c
Normal 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);
|
||||
}
|
||||
}
|
572
drivers/filters/mountmgr/point.c
Normal file
572
drivers/filters/mountmgr/point.c
Normal 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;
|
||||
}
|
1004
drivers/filters/mountmgr/symlink.c
Normal file
1004
drivers/filters/mountmgr/symlink.c
Normal file
File diff suppressed because it is too large
Load diff
436
drivers/filters/mountmgr/uniqueid.c
Normal file
436
drivers/filters/mountmgr/uniqueid.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue