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)
36 ChangeUniqueIdRoutine(IN PWSTR ValueName
,
41 IN PVOID EntryContext
)
43 PMOUNTDEV_UNIQUE_ID OldUniqueId
= Context
;
44 PMOUNTDEV_UNIQUE_ID NewUniqueId
= EntryContext
;
46 /* Validate parameters not to corrupt registry */
47 if ((ValueType
!= REG_BINARY
) ||
48 (OldUniqueId
->UniqueIdLength
!= ValueLength
))
50 return STATUS_SUCCESS
;
53 if (RtlCompareMemory(OldUniqueId
->UniqueId
, ValueData
, ValueLength
) == ValueLength
)
56 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
61 NewUniqueId
->UniqueIdLength
);
64 return STATUS_SUCCESS
;
71 MountMgrUniqueIdChangeRoutine(IN PDEVICE_EXTENSION DeviceExtension
,
72 IN PMOUNTDEV_UNIQUE_ID OldUniqueId
,
73 IN PMOUNTDEV_UNIQUE_ID NewUniqueId
)
77 PUNIQUE_ID_REPLICATE DuplicateId
;
78 PDEVICE_INFORMATION DeviceInformation
;
79 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
80 PMOUNTDEV_UNIQUE_ID UniqueId
, NewDuplicateId
;
81 PLIST_ENTRY ListHead
, NextEntry
, ReplicatedHead
, NextReplicated
;
83 /* Synchronise with remote databases */
84 Status
= WaitForRemoteDatabaseSemaphore(DeviceExtension
);
85 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
87 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
88 QueryTable
[0].QueryRoutine
= ChangeUniqueIdRoutine
;
89 QueryTable
[0].EntryContext
= NewUniqueId
;
92 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
98 /* Browse all the devices to find the one that
99 * owns the old unique ID
101 ListHead
= &(DeviceExtension
->DeviceListHead
);
102 NextEntry
= ListHead
->Flink
;
103 while (ListHead
!= NextEntry
)
105 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
109 if (DeviceInformation
->UniqueId
->UniqueIdLength
== OldUniqueId
->UniqueIdLength
&&
110 RtlCompareMemory(OldUniqueId
->UniqueId
,
111 DeviceInformation
->UniqueId
->UniqueId
,
112 OldUniqueId
->UniqueIdLength
) == OldUniqueId
->UniqueIdLength
)
117 NextEntry
= NextEntry
->Flink
;
120 /* If we didn't find any release everything and quit */
121 if (ListHead
== NextEntry
)
123 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
126 if (NT_SUCCESS(Status
))
128 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
134 /* If lock failed, then, just update this database */
135 if (!NT_SUCCESS(Status
))
137 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
138 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
143 /* Allocate new unique ID */
144 UniqueId
= AllocatePool(NewUniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
147 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
149 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
153 /* Release old one */
154 FreePool(DeviceInformation
->UniqueId
);
155 /* And set new one */
156 DeviceInformation
->UniqueId
= UniqueId
;
157 UniqueId
->UniqueIdLength
= NewUniqueId
->UniqueIdLength
;
158 RtlCopyMemory(UniqueId
->UniqueId
, NewUniqueId
->UniqueId
, NewUniqueId
->UniqueIdLength
);
160 /* Now, check if it's required to update replicated unique IDs as well */
161 ListHead
= &(DeviceExtension
->DeviceListHead
);
162 NextEntry
= ListHead
->Flink
;
163 while (ListHead
!= NextEntry
)
165 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
168 ResyncNeeded
= FALSE
;
170 ReplicatedHead
= &(DeviceInformation
->ReplicatedUniqueIdsListHead
);
171 NextReplicated
= ReplicatedHead
->Flink
;
172 while (ReplicatedHead
!= NextReplicated
)
174 DuplicateId
= CONTAINING_RECORD(NextReplicated
,
176 ReplicatedUniqueIdsListEntry
);
178 if (DuplicateId
->UniqueId
->UniqueIdLength
== OldUniqueId
->UniqueIdLength
)
180 if (RtlCompareMemory(DuplicateId
->UniqueId
->UniqueId
,
181 OldUniqueId
->UniqueId
,
182 OldUniqueId
->UniqueIdLength
) == OldUniqueId
->UniqueIdLength
)
184 /* It was our old unique ID */
185 NewDuplicateId
= AllocatePool(NewUniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
190 FreePool(DuplicateId
->UniqueId
);
192 DuplicateId
->UniqueId
= NewDuplicateId
;
193 DuplicateId
->UniqueId
->UniqueIdLength
= NewUniqueId
->UniqueIdLength
;
194 RtlCopyMemory(NewDuplicateId
->UniqueId
, NewUniqueId
->UniqueId
, NewUniqueId
->UniqueIdLength
);
199 NextReplicated
= NextReplicated
->Flink
;
202 /* If resync is required on this device, do it */
205 ChangeRemoteDatabaseUniqueId(DeviceInformation
, OldUniqueId
, NewUniqueId
);
208 NextEntry
= NextEntry
->Flink
;
211 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
212 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
221 IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension
,
222 IN PDATABASE_ENTRY DatabaseEntry
)
224 PLIST_ENTRY NextEntry
;
225 PDEVICE_INFORMATION DeviceInformation
;
227 /* If no device, no unique ID (O'rly?!)
233 if (IsListEmpty(&(DeviceExtension
->DeviceListHead
)))
238 /* Now we know that we have devices, find the one */
239 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
240 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
241 NextEntry
= NextEntry
->Flink
)
243 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
247 if (DeviceInformation
->UniqueId
->UniqueIdLength
!= DatabaseEntry
->UniqueIdLength
)
253 if (RtlCompareMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
254 DeviceInformation
->UniqueId
->UniqueId
,
255 DatabaseEntry
->UniqueIdLength
) == DatabaseEntry
->UniqueIdLength
)
269 CreateNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
273 UNICODE_STRING GuidString
;
275 /* Entry with no drive letter are made that way:
276 * Instead of having a path with the letter,
277 * you have GUID with the unique ID.
279 if (!NT_SUCCESS(ExUuidCreate(&Guid
)))
284 /* Convert to string */
285 if (!NT_SUCCESS(RtlStringFromGUID(&Guid
, &GuidString
)))
290 /* No letter entries must start with #, so allocate a proper string */
291 String
= AllocatePool(GuidString
.Length
+ 2 * sizeof(WCHAR
));
294 ExFreePoolWithTag(GuidString
.Buffer
, 0);
298 /* Write the complete string */
300 RtlCopyMemory(String
+ 1, GuidString
.Buffer
, GuidString
.Length
);
301 String
[GuidString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
303 /* Don't need that one anymore */
304 ExFreePoolWithTag(GuidString
.Buffer
, 0);
306 /* Write the entry */
307 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
312 UniqueId
->UniqueIdLength
);
324 CheckForNoDriveLetterEntry(IN PWSTR ValueName
,
327 IN ULONG ValueLength
,
329 IN PVOID EntryContext
)
331 PBOOLEAN EntryPresent
= EntryContext
;
332 PMOUNTDEV_UNIQUE_ID UniqueId
= Context
;
334 /* Check if matches no drive letter entry */
335 if (ValueName
[0] != L
'#' || ValueType
!= REG_BINARY
||
336 UniqueId
->UniqueIdLength
!= ValueLength
)
338 return STATUS_SUCCESS
;
341 /* Compare unique ID */
342 if (RtlCompareMemory(UniqueId
->UniqueId
, ValueData
, ValueLength
) == ValueLength
)
344 *EntryPresent
= TRUE
;
347 return STATUS_SUCCESS
;
354 HasNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
356 BOOLEAN EntryPresent
= FALSE
;
357 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
359 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
360 QueryTable
[0].QueryRoutine
= CheckForNoDriveLetterEntry
;
361 QueryTable
[0].EntryContext
= &EntryPresent
;
363 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
376 UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation
, IN PDATABASE_ENTRY DatabaseEntry
)
378 PLIST_ENTRY NextEntry
;
379 PUNIQUE_ID_REPLICATE ReplicatedUniqueId
, NewEntry
;
381 /* Browse all the device replicated unique IDs */
382 for (NextEntry
= DeviceInformation
->ReplicatedUniqueIdsListHead
.Flink
;
383 NextEntry
!= &(DeviceInformation
->ReplicatedUniqueIdsListHead
);
384 NextEntry
= NextEntry
->Flink
)
386 ReplicatedUniqueId
= CONTAINING_RECORD(NextEntry
,
388 ReplicatedUniqueIdsListEntry
);
390 if (ReplicatedUniqueId
->UniqueId
->UniqueIdLength
!= DatabaseEntry
->UniqueIdLength
)
395 /* If we find the UniqueId to update, break */
396 if (RtlCompareMemory(ReplicatedUniqueId
->UniqueId
->UniqueId
,
397 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
398 ReplicatedUniqueId
->UniqueId
->UniqueIdLength
) == ReplicatedUniqueId
->UniqueId
->UniqueIdLength
)
404 /* We found the unique ID, no need to continue */
405 if (NextEntry
!= &(DeviceInformation
->ReplicatedUniqueIdsListHead
))
410 /* Allocate a new entry for unique ID */
411 NewEntry
= AllocatePool(sizeof(UNIQUE_ID_REPLICATE
));
417 /* Allocate the unique ID */
418 NewEntry
->UniqueId
= AllocatePool(DatabaseEntry
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
419 if (!NewEntry
->UniqueId
)
426 NewEntry
->UniqueId
->UniqueIdLength
= DatabaseEntry
->UniqueIdLength
;
427 RtlCopyMemory(NewEntry
->UniqueId
->UniqueId
,
428 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
429 DatabaseEntry
->UniqueIdLength
);
430 /* And insert into replicated unique IDs list */
431 InsertTailList(&DeviceInformation
->ReplicatedUniqueIdsListHead
, &NewEntry
->ReplicatedUniqueIdsListEntry
);