3 * Copyright (C) 2011 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/uniqueid.c
22 * PURPOSE: Mount Manager - Unique ID
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
26 /* INCLUDES *****************************************************************/
38 ChangeUniqueIdRoutine(IN PWSTR ValueName
,
43 IN PVOID EntryContext
)
45 PMOUNTDEV_UNIQUE_ID OldUniqueId
= Context
;
46 PMOUNTDEV_UNIQUE_ID NewUniqueId
= EntryContext
;
48 /* Validate parameters not to corrupt registry */
49 if ((ValueType
!= REG_BINARY
) ||
50 (OldUniqueId
->UniqueIdLength
!= ValueLength
))
52 return STATUS_SUCCESS
;
55 if (RtlCompareMemory(OldUniqueId
->UniqueId
, ValueData
, ValueLength
) == ValueLength
)
58 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
63 NewUniqueId
->UniqueIdLength
);
66 return STATUS_SUCCESS
;
73 MountMgrUniqueIdChangeRoutine(IN PDEVICE_EXTENSION DeviceExtension
,
74 IN PMOUNTDEV_UNIQUE_ID OldUniqueId
,
75 IN PMOUNTDEV_UNIQUE_ID NewUniqueId
)
79 PUNIQUE_ID_REPLICATE DuplicateId
;
80 PDEVICE_INFORMATION DeviceInformation
;
81 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
82 PMOUNTDEV_UNIQUE_ID UniqueId
, NewDuplicateId
;
83 PLIST_ENTRY ListHead
, NextEntry
, ReplicatedHead
, NextReplicated
;
85 /* Synchronise with remote databases */
86 Status
= WaitForRemoteDatabaseSemaphore(DeviceExtension
);
87 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
89 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
90 QueryTable
[0].QueryRoutine
= ChangeUniqueIdRoutine
;
91 QueryTable
[0].EntryContext
= NewUniqueId
;
94 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
100 /* Browse all the devices to find the one that
101 * owns the old unique ID
103 ListHead
= &(DeviceExtension
->DeviceListHead
);
104 NextEntry
= ListHead
->Flink
;
105 while (ListHead
!= NextEntry
)
107 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
111 if (DeviceInformation
->UniqueId
->UniqueIdLength
== OldUniqueId
->UniqueIdLength
&&
112 RtlCompareMemory(OldUniqueId
->UniqueId
,
113 DeviceInformation
->UniqueId
->UniqueId
,
114 OldUniqueId
->UniqueIdLength
) == OldUniqueId
->UniqueIdLength
)
119 NextEntry
= NextEntry
->Flink
;
122 /* If we didn't find any release everything and quit */
123 if (ListHead
== NextEntry
)
125 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
128 if (NT_SUCCESS(Status
))
130 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
136 /* If lock failed, then, just update this database */
137 if (!NT_SUCCESS(Status
))
139 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
140 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
145 /* Allocate new unique ID */
146 UniqueId
= AllocatePool(NewUniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
149 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
151 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
155 /* Release old one */
156 FreePool(DeviceInformation
->UniqueId
);
157 /* And set new one */
158 DeviceInformation
->UniqueId
= UniqueId
;
159 UniqueId
->UniqueIdLength
= NewUniqueId
->UniqueIdLength
;
160 RtlCopyMemory(UniqueId
->UniqueId
, NewUniqueId
->UniqueId
, NewUniqueId
->UniqueIdLength
);
162 /* Now, check if it's required to update replicated unique IDs as well */
163 ListHead
= &(DeviceExtension
->DeviceListHead
);
164 NextEntry
= ListHead
->Flink
;
165 while (ListHead
!= NextEntry
)
167 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
170 ResyncNeeded
= FALSE
;
172 ReplicatedHead
= &(DeviceInformation
->ReplicatedUniqueIdsListHead
);
173 NextReplicated
= ReplicatedHead
->Flink
;
174 while (ReplicatedHead
!= NextReplicated
)
176 DuplicateId
= CONTAINING_RECORD(NextReplicated
,
178 ReplicatedUniqueIdsListEntry
);
180 if (DuplicateId
->UniqueId
->UniqueIdLength
== OldUniqueId
->UniqueIdLength
)
182 if (RtlCompareMemory(DuplicateId
->UniqueId
->UniqueId
,
183 OldUniqueId
->UniqueId
,
184 OldUniqueId
->UniqueIdLength
) == OldUniqueId
->UniqueIdLength
)
186 /* It was our old unique ID */
187 NewDuplicateId
= AllocatePool(NewUniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
192 FreePool(DuplicateId
->UniqueId
);
194 DuplicateId
->UniqueId
= NewDuplicateId
;
195 DuplicateId
->UniqueId
->UniqueIdLength
= NewUniqueId
->UniqueIdLength
;
196 RtlCopyMemory(NewDuplicateId
->UniqueId
, NewUniqueId
->UniqueId
, NewUniqueId
->UniqueIdLength
);
201 NextReplicated
= NextReplicated
->Flink
;
204 /* If resync is required on this device, do it */
207 ChangeRemoteDatabaseUniqueId(DeviceInformation
, OldUniqueId
, NewUniqueId
);
210 NextEntry
= NextEntry
->Flink
;
213 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
214 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
223 IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension
,
224 IN PDATABASE_ENTRY DatabaseEntry
)
226 PLIST_ENTRY NextEntry
;
227 PDEVICE_INFORMATION DeviceInformation
;
229 /* If no device, no unique ID (O'rly?!)
235 if (IsListEmpty(&(DeviceExtension
->DeviceListHead
)))
240 /* Now we know that we have devices, find the one */
241 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
242 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
243 NextEntry
= NextEntry
->Flink
)
245 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
249 if (DeviceInformation
->UniqueId
->UniqueIdLength
!= DatabaseEntry
->UniqueIdLength
)
255 if (RtlCompareMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
256 DeviceInformation
->UniqueId
->UniqueId
,
257 DatabaseEntry
->UniqueIdLength
) == DatabaseEntry
->UniqueIdLength
)
271 CreateNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
275 UNICODE_STRING GuidString
;
277 /* Entry with no drive letter are made that way:
278 * Instead of having a path with the letter,
279 * you have GUID with the unique ID.
281 if (!NT_SUCCESS(ExUuidCreate(&Guid
)))
286 /* Convert to string */
287 if (!NT_SUCCESS(RtlStringFromGUID(&Guid
, &GuidString
)))
292 /* No letter entries must start with #, so allocate a proper string */
293 String
= AllocatePool(GuidString
.Length
+ 2 * sizeof(WCHAR
));
296 ExFreePoolWithTag(GuidString
.Buffer
, 0);
300 /* Write the complete string */
302 RtlCopyMemory(String
+ 1, GuidString
.Buffer
, GuidString
.Length
);
303 String
[GuidString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
305 /* Don't need that one anymore */
306 ExFreePoolWithTag(GuidString
.Buffer
, 0);
308 /* Write the entry */
309 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
314 UniqueId
->UniqueIdLength
);
326 CheckForNoDriveLetterEntry(IN PWSTR ValueName
,
329 IN ULONG ValueLength
,
331 IN PVOID EntryContext
)
333 PBOOLEAN EntryPresent
= EntryContext
;
334 PMOUNTDEV_UNIQUE_ID UniqueId
= Context
;
336 /* Check if matches no drive letter entry */
337 if (ValueName
[0] != L
'#' || ValueType
!= REG_BINARY
||
338 UniqueId
->UniqueIdLength
!= ValueLength
)
340 return STATUS_SUCCESS
;
343 /* Compare unique ID */
344 if (RtlCompareMemory(UniqueId
->UniqueId
, ValueData
, ValueLength
) == ValueLength
)
346 *EntryPresent
= TRUE
;
349 return STATUS_SUCCESS
;
356 HasNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
358 BOOLEAN EntryPresent
= FALSE
;
359 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
361 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
362 QueryTable
[0].QueryRoutine
= CheckForNoDriveLetterEntry
;
363 QueryTable
[0].EntryContext
= &EntryPresent
;
365 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
378 UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation
, IN PDATABASE_ENTRY DatabaseEntry
)
380 PLIST_ENTRY NextEntry
;
381 PUNIQUE_ID_REPLICATE ReplicatedUniqueId
, NewEntry
;
383 /* Browse all the device replicated unique IDs */
384 for (NextEntry
= DeviceInformation
->ReplicatedUniqueIdsListHead
.Flink
;
385 NextEntry
!= &(DeviceInformation
->ReplicatedUniqueIdsListHead
);
386 NextEntry
= NextEntry
->Flink
)
388 ReplicatedUniqueId
= CONTAINING_RECORD(NextEntry
,
390 ReplicatedUniqueIdsListEntry
);
392 if (ReplicatedUniqueId
->UniqueId
->UniqueIdLength
!= DatabaseEntry
->UniqueIdLength
)
397 /* If we find the UniqueId to update, break */
398 if (RtlCompareMemory(ReplicatedUniqueId
->UniqueId
->UniqueId
,
399 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
400 ReplicatedUniqueId
->UniqueId
->UniqueIdLength
) == ReplicatedUniqueId
->UniqueId
->UniqueIdLength
)
406 /* We found the unique ID, no need to continue */
407 if (NextEntry
!= &(DeviceInformation
->ReplicatedUniqueIdsListHead
))
412 /* Allocate a new entry for unique ID */
413 NewEntry
= AllocatePool(sizeof(UNIQUE_ID_REPLICATE
));
419 /* Allocate the unique ID */
420 NewEntry
->UniqueId
= AllocatePool(DatabaseEntry
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
421 if (!NewEntry
->UniqueId
)
428 NewEntry
->UniqueId
->UniqueIdLength
= DatabaseEntry
->UniqueIdLength
;
429 RtlCopyMemory(NewEntry
->UniqueId
->UniqueId
,
430 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
431 DatabaseEntry
->UniqueIdLength
);
432 /* And insert into replicated unique IDs list */
433 InsertTailList(&DeviceInformation
->ReplicatedUniqueIdsListHead
, &NewEntry
->ReplicatedUniqueIdsListEntry
);