Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435/* * 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) */
#include "mntmgr.h"
#define NDEBUG#include <debug.h>
/* * @implemented */NTSTATUSNTAPIChangeUniqueIdRoutine(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 */VOIDMountMgrUniqueIdChangeRoutine(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 */BOOLEANIsUniqueIdPresent(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 */VOIDCreateNoDriveLetterEntry(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 */NTSTATUSNTAPICheckForNoDriveLetterEntry(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 */BOOLEANHasNoDriveLetterEntry(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 */VOIDUpdateReplicatedUniqueIds(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;}