ReactOS  0.4.14-dev-50-g13bb5e2
uniqueid.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 2011 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  *
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)
24  */
25 
26 #include "mntmgr.h"
27 
28 #define NDEBUG
29 #include <debug.h>
30 
31 /*
32  * @implemented
33  */
35 NTAPI
42 {
43  PMOUNTDEV_UNIQUE_ID OldUniqueId = Context;
44  PMOUNTDEV_UNIQUE_ID NewUniqueId = EntryContext;
45 
46  /* Validate parameters not to corrupt registry */
47  if ((ValueType != REG_BINARY) ||
48  (OldUniqueId->UniqueIdLength != ValueLength))
49  {
50  return STATUS_SUCCESS;
51  }
52 
54  {
55  /* Write new data */
58  ValueName,
59  REG_BINARY,
60  NewUniqueId,
61  NewUniqueId->UniqueIdLength);
62  }
63 
64  return STATUS_SUCCESS;
65 }
66 
67 /*
68  * @implemented
69  */
70 VOID
72  IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
73  IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
74 {
76  BOOLEAN ResyncNeeded;
77  PUNIQUE_ID_REPLICATE DuplicateId;
78  PDEVICE_INFORMATION DeviceInformation;
80  PMOUNTDEV_UNIQUE_ID UniqueId, NewDuplicateId;
81  PLIST_ENTRY ListHead, NextEntry, ReplicatedHead, NextReplicated;
82 
83  /* Synchronise with remote databases */
84  Status = WaitForRemoteDatabaseSemaphore(DeviceExtension);
85  KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
86 
89  QueryTable[0].EntryContext = NewUniqueId;
90 
91  /* Write new data */
94  QueryTable,
95  OldUniqueId,
96  NULL);
97 
98  /* Browse all the devices to find the one that
99  * owns the old unique ID
100  */
101  ListHead = &(DeviceExtension->DeviceListHead);
102  NextEntry = ListHead->Flink;
103  while (ListHead != NextEntry)
104  {
105  DeviceInformation = CONTAINING_RECORD(NextEntry,
107  DeviceListEntry);
108 
109  if (DeviceInformation->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength &&
110  RtlCompareMemory(OldUniqueId->UniqueId,
111  DeviceInformation->UniqueId->UniqueId,
112  OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength)
113  {
114  break;
115  }
116 
117  NextEntry = NextEntry->Flink;
118  }
119 
120  /* If we didn't find any release everything and quit */
121  if (ListHead == NextEntry)
122  {
123  KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
124  1, FALSE);
125 
126  if (NT_SUCCESS(Status))
127  {
128  ReleaseRemoteDatabaseSemaphore(DeviceExtension);
129  }
130 
131  return;
132  }
133 
134  /* If lock failed, then, just update this database */
135  if (!NT_SUCCESS(Status))
136  {
137  ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
138  KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
139  1, FALSE);
140  return;
141  }
142 
143  /* Allocate new unique ID */
144  UniqueId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
145  if (!UniqueId)
146  {
147  KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
148  1, FALSE);
149  ReleaseRemoteDatabaseSemaphore(DeviceExtension);
150  return;
151  }
152 
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);
159 
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)
164  {
165  DeviceInformation = CONTAINING_RECORD(NextEntry,
167  DeviceListEntry);
168  ResyncNeeded = FALSE;
169 
170  ReplicatedHead = &(DeviceInformation->ReplicatedUniqueIdsListHead);
171  NextReplicated = ReplicatedHead->Flink;
172  while (ReplicatedHead != NextReplicated)
173  {
174  DuplicateId = CONTAINING_RECORD(NextReplicated,
176  ReplicatedUniqueIdsListEntry);
177 
178  if (DuplicateId->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength)
179  {
180  if (RtlCompareMemory(DuplicateId->UniqueId->UniqueId,
181  OldUniqueId->UniqueId,
182  OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength)
183  {
184  /* It was our old unique ID */
185  NewDuplicateId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
186  if (NewDuplicateId)
187  {
188  /* Update it */
189  ResyncNeeded = TRUE;
190  FreePool(DuplicateId->UniqueId);
191 
192  DuplicateId->UniqueId = NewDuplicateId;
193  DuplicateId->UniqueId->UniqueIdLength = NewUniqueId->UniqueIdLength;
194  RtlCopyMemory(NewDuplicateId->UniqueId, NewUniqueId->UniqueId, NewUniqueId->UniqueIdLength);
195  }
196  }
197  }
198 
199  NextReplicated = NextReplicated->Flink;
200  }
201 
202  /* If resync is required on this device, do it */
203  if (ResyncNeeded)
204  {
205  ChangeRemoteDatabaseUniqueId(DeviceInformation, OldUniqueId, NewUniqueId);
206  }
207 
208  NextEntry = NextEntry->Flink;
209  }
210 
211  KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
212  ReleaseRemoteDatabaseSemaphore(DeviceExtension);
213 
214  return;
215 }
216 
217 /*
218  * @implemented
219  */
220 BOOLEAN
222  IN PDATABASE_ENTRY DatabaseEntry)
223 {
224  PLIST_ENTRY NextEntry;
225  PDEVICE_INFORMATION DeviceInformation;
226 
227  /* If no device, no unique ID (O'rly?!)
228  * ./)/).
229  * (°-°)
230  * (___) ORLY?
231  * " "
232  */
233  if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
234  {
235  return FALSE;
236  }
237 
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)
242  {
243  DeviceInformation = CONTAINING_RECORD(NextEntry,
245  DeviceListEntry);
246 
247  if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
248  {
249  continue;
250  }
251 
252  /* It's matching! */
253  if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
254  DeviceInformation->UniqueId->UniqueId,
255  DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
256  {
257  return TRUE;
258  }
259  }
260 
261  /* No luck... */
262  return FALSE;
263 }
264 
265 /*
266  * @implemented
267  */
268 VOID
270 {
271  UUID Guid;
272  PWCHAR String;
274 
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.
278  */
279  if (!NT_SUCCESS(ExUuidCreate(&Guid)))
280  {
281  return;
282  }
283 
284  /* Convert to string */
286  {
287  return;
288  }
289 
290  /* No letter entries must start with #, so allocate a proper string */
291  String = AllocatePool(GuidString.Length + 2 * sizeof(WCHAR));
292  if (!String)
293  {
294  ExFreePoolWithTag(GuidString.Buffer, 0);
295  return;
296  }
297 
298  /* Write the complete string */
299  String[0] = L'#';
300  RtlCopyMemory(String + 1, GuidString.Buffer, GuidString.Length);
301  String[GuidString.Length / sizeof(WCHAR)] = UNICODE_NULL;
302 
303  /* Don't need that one anymore */
304  ExFreePoolWithTag(GuidString.Buffer, 0);
305 
306  /* Write the entry */
308  DatabasePath,
309  String,
310  REG_BINARY,
311  UniqueId->UniqueId,
312  UniqueId->UniqueIdLength);
313 
314  FreePool(String);
315 
316  return;
317 }
318 
319 /*
320  * @implemented
321  */
322 NTSTATUS
323 NTAPI
328  IN PVOID Context,
330 {
331  PBOOLEAN EntryPresent = EntryContext;
332  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
333 
334  /* Check if matches no drive letter entry */
335  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
336  UniqueId->UniqueIdLength != ValueLength)
337  {
338  return STATUS_SUCCESS;
339  }
340 
341  /* Compare unique ID */
343  {
344  *EntryPresent = TRUE;
345  }
346 
347  return STATUS_SUCCESS;
348 }
349 
350 /*
351  * @implemented
352  */
353 BOOLEAN
355 {
356  BOOLEAN EntryPresent = FALSE;
358 
361  QueryTable[0].EntryContext = &EntryPresent;
362 
364  DatabasePath,
365  QueryTable,
366  UniqueId,
367  NULL);
368 
369  return EntryPresent;
370 }
371 
372 /*
373  * @implemented
374  */
375 VOID
377 {
378  PLIST_ENTRY NextEntry;
379  PUNIQUE_ID_REPLICATE ReplicatedUniqueId, NewEntry;
380 
381  /* Browse all the device replicated unique IDs */
382  for (NextEntry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink;
383  NextEntry != &(DeviceInformation->ReplicatedUniqueIdsListHead);
384  NextEntry = NextEntry->Flink)
385  {
386  ReplicatedUniqueId = CONTAINING_RECORD(NextEntry,
388  ReplicatedUniqueIdsListEntry);
389 
390  if (ReplicatedUniqueId->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
391  {
392  continue;
393  }
394 
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)
399  {
400  break;
401  }
402  }
403 
404  /* We found the unique ID, no need to continue */
405  if (NextEntry != &(DeviceInformation->ReplicatedUniqueIdsListHead))
406  {
407  return;
408  }
409 
410  /* Allocate a new entry for unique ID */
411  NewEntry = AllocatePool(sizeof(UNIQUE_ID_REPLICATE));
412  if (!NewEntry)
413  {
414  return;
415  }
416 
417  /* Allocate the unique ID */
418  NewEntry->UniqueId = AllocatePool(DatabaseEntry->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
419  if (!NewEntry->UniqueId)
420  {
421  FreePool(NewEntry);
422  return;
423  }
424 
425  /* Copy */
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);
432 
433  return;
434 }
static PWSTR GuidString
Definition: apphelp.c:91
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:82
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4004
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define REG_BINARY
Definition: nt_native.h:1496
uint16_t * PWSTR
Definition: typedefs.h:54
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4016
LONG NTSTATUS
Definition: precomp.h:26
USHORT UniqueIdLength
Definition: imports.h:138
NTSTATUS NTAPI CheckForNoDriveLetterEntry(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: uniqueid.c:324
NTSTATUS NTAPI ChangeUniqueIdRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: uniqueid.c:36
static WCHAR String[]
Definition: stringtable.c:55
uint16_t * PWCHAR
Definition: typedefs.h:54
#define InsertTailList(ListHead, Entry)
#define FreePool(P)
Definition: mntmgr.h:154
BOOLEAN IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:221
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
uint32_t ULONG_PTR
Definition: typedefs.h:63
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
VOID ReconcileThisDatabaseWithMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1595
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define UNICODE_NULL
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4004
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
NTKERNELAPI NTSTATUS ExUuidCreate(OUT UUID *Uuid)
Definition: uuid.c:385
VOID MountMgrUniqueIdChangeRoutine(IN PDEVICE_EXTENSION DeviceExtension, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
Definition: uniqueid.c:71
VOID CreateNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: uniqueid.c:269
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
VOID ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
Definition: database.c:1891
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
Definition: mntmgr.h:85
char * PBOOLEAN
Definition: retypes.h:11
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
VOID UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:376
static const WCHAR L[]
Definition: oid.c:1250
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
Definition: typedefs.h:117
NTSYSAPI NTSTATUS WINAPI RtlStringFromGUID(REFGUID, PUNICODE_STRING)
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define AllocatePool(Size)
Definition: mntmgr.h:153
PWSTR DatabasePath
Definition: database.c:31
Status
Definition: gdiplustypes.h:24
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
NTSTATUS WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:371
LIST_ENTRY ReplicatedUniqueIdsListHead
Definition: mntmgr.h:46
struct tagContext Context
Definition: acpixf.h:1024
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
BOOLEAN HasNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: uniqueid.c:354
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
VOID ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:391
return STATUS_SUCCESS
Definition: btrfs.c:2966
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:49
UCHAR UniqueId[1]
Definition: imports.h:139
LIST_ENTRY ReplicatedUniqueIdsListEntry
Definition: mntmgr.h:81
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465