xref: /reactos/drivers/storage/mountmgr/point.c (revision 003b19dc)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2011-2012 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/point.c
22  * PURPOSE:          Mount Manager - Mount points
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  */
34 NTSTATUS
35 MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension,
36                           IN PUNICODE_STRING SymbolicLinkName,
37                           IN PUNICODE_STRING DeviceName)
38 {
39     NTSTATUS Status;
40     PLIST_ENTRY DeviceEntry;
41     PMOUNTDEV_UNIQUE_ID UniqueId;
42     PSYMLINK_INFORMATION SymlinkInformation;
43     UNICODE_STRING SymLink, TargetDeviceName;
44     PDEVICE_INFORMATION DeviceInformation = NULL, DeviceInfo;
45 
46     /* Get device name */
47     Status = QueryDeviceInformation(DeviceName,
48                                     &TargetDeviceName,
49                                     NULL, NULL, NULL,
50                                     NULL, NULL, NULL);
51     if (!NT_SUCCESS(Status))
52     {
53         return Status;
54     }
55 
56     /* First of all, try to find device */
57     for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
58          DeviceEntry != &(DeviceExtension->DeviceListHead);
59          DeviceEntry = DeviceEntry->Flink)
60     {
61         DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
62 
63         if (RtlEqualUnicodeString(&TargetDeviceName, &(DeviceInformation->DeviceName), TRUE))
64         {
65             break;
66         }
67     }
68 
69     /* Copy symbolic link name and null terminate it */
70     SymLink.Buffer = AllocatePool(SymbolicLinkName->Length + sizeof(UNICODE_NULL));
71     if (!SymLink.Buffer)
72     {
73         FreePool(TargetDeviceName.Buffer);
74         return STATUS_INSUFFICIENT_RESOURCES;
75     }
76 
77     RtlCopyMemory(SymLink.Buffer, SymbolicLinkName->Buffer, SymbolicLinkName->Length);
78     SymLink.Buffer[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
79     SymLink.Length = SymbolicLinkName->Length;
80     SymLink.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL);
81 
82     /* If we didn't find device */
83     if (DeviceEntry == &(DeviceExtension->DeviceListHead))
84     {
85         /* Then, try with unique ID */
86         Status = QueryDeviceInformation(SymbolicLinkName,
87                                         NULL, &UniqueId,
88                                         NULL, NULL, NULL,
89                                         NULL, NULL);
90         if (!NT_SUCCESS(Status))
91         {
92             FreePool(TargetDeviceName.Buffer);
93             FreePool(SymLink.Buffer);
94             return Status;
95         }
96 
97         /* Create a link to the device */
98         Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
99         if (!NT_SUCCESS(Status))
100         {
101             FreePool(UniqueId);
102             FreePool(TargetDeviceName.Buffer);
103             FreePool(SymLink.Buffer);
104             return Status;
105         }
106 
107         /* If caller provided driver letter, delete it */
108         if (IsDriveLetter(&SymLink))
109         {
110             DeleteRegistryDriveLetter(UniqueId);
111         }
112 
113         /* Device will be identified with its unique ID */
114         Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
115                                        DatabasePath,
116                                        SymLink.Buffer,
117                                        REG_BINARY,
118                                        UniqueId->UniqueId,
119                                        UniqueId->UniqueIdLength);
120 
121         FreePool(UniqueId);
122         FreePool(TargetDeviceName.Buffer);
123         FreePool(SymLink.Buffer);
124         return Status;
125     }
126 
127     /* If call provided a driver letter whereas device already has one
128      * fail, this is not doable
129      */
130     if (IsDriveLetter(&SymLink) && HasDriveLetter(DeviceInformation))
131     {
132         FreePool(TargetDeviceName.Buffer);
133         FreePool(SymLink.Buffer);
134         return STATUS_INVALID_PARAMETER;
135     }
136 
137     /* Now, create a link */
138     Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
139     FreePool(TargetDeviceName.Buffer);
140     if (!NT_SUCCESS(Status))
141     {
142         FreePool(SymLink.Buffer);
143         return Status;
144     }
145 
146     /* Associate Unique ID <-> symbolic name */
147     UniqueId = DeviceInformation->UniqueId;
148     Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
149                                    DatabasePath,
150                                    SymLink.Buffer,
151                                    REG_BINARY,
152                                    UniqueId->UniqueId,
153                                    UniqueId->UniqueIdLength);
154     if (!NT_SUCCESS(Status))
155     {
156         GlobalDeleteSymbolicLink(&SymLink);
157         FreePool(SymLink.Buffer);
158         return Status;
159     }
160 
161     /* Now, prepare to save the link with the device */
162     SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
163     if (!SymlinkInformation)
164     {
165         Status = STATUS_INSUFFICIENT_RESOURCES;
166         GlobalDeleteSymbolicLink(&SymLink);
167         FreePool(SymLink.Buffer);
168         return Status;
169     }
170 
171     SymlinkInformation->Name.Length = SymLink.Length;
172     SymlinkInformation->Name.MaximumLength = SymLink.Length + sizeof(UNICODE_NULL);
173     SymlinkInformation->Name.Buffer = AllocatePool(SymlinkInformation->Name.MaximumLength);
174     if (!SymlinkInformation->Name.Buffer)
175     {
176         Status = STATUS_INSUFFICIENT_RESOURCES;
177         FreePool(SymlinkInformation);
178         GlobalDeleteSymbolicLink(&SymLink);
179         FreePool(SymLink.Buffer);
180         return Status;
181     }
182 
183     /* Save the link and mark it online */
184     RtlCopyMemory(SymlinkInformation->Name.Buffer, SymLink.Buffer, SymlinkInformation->Name.Length);
185     SymlinkInformation->Name.Buffer[SymlinkInformation->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
186     SymlinkInformation->Online = TRUE;
187     InsertTailList(&DeviceInformation->SymbolicLinksListHead, &SymlinkInformation->SymbolicLinksListEntry);
188     SendLinkCreated(&(SymlinkInformation->Name));
189 
190     /* If we have a drive letter */
191     if (IsDriveLetter(&SymLink))
192     {
193         /* Then, delete the no drive letter entry */
194         DeleteNoDriveLetterEntry(UniqueId);
195 
196         /* And post online notification if asked */
197         if (!DeviceInformation->SkipNotifications)
198         {
199             PostOnlineNotification(DeviceExtension, &DeviceInformation->SymbolicName);
200         }
201     }
202 
203     /* If that's a volume with automatic drive letter, it's now time to resync databases */
204     if (MOUNTMGR_IS_VOLUME_NAME(&SymLink) && DeviceExtension->AutomaticDriveLetter)
205     {
206         for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
207              DeviceEntry != &(DeviceExtension->DeviceListHead);
208              DeviceEntry = DeviceEntry->Flink)
209         {
210             DeviceInfo = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
211 
212             /* If there's one, ofc! */
213             if (!DeviceInfo->NoDatabase)
214             {
215                 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInfo);
216             }
217         }
218     }
219 
220     /* Notify & quit */
221     FreePool(SymLink.Buffer);
222     MountMgrNotify(DeviceExtension);
223 
224     if (!DeviceInformation->ManuallyRegistered)
225     {
226         MountMgrNotifyNameChange(DeviceExtension, DeviceName, FALSE);
227     }
228 
229     return Status;
230 }
231 
232 /*
233  * @implemented
234  */
235 NTSTATUS
236 QueryPointsFromMemory(IN PDEVICE_EXTENSION DeviceExtension,
237                       IN PIRP Irp,
238                       IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL,
239                       IN PUNICODE_STRING SymbolicName OPTIONAL)
240 {
241     NTSTATUS Status;
242     PIO_STACK_LOCATION Stack;
243     UNICODE_STRING DeviceName;
244     PMOUNTMGR_MOUNT_POINTS MountPoints;
245     PDEVICE_INFORMATION DeviceInformation;
246     PLIST_ENTRY DeviceEntry, SymlinksEntry;
247     PSYMLINK_INFORMATION SymlinkInformation;
248     USHORT UniqueIdLength, DeviceNameLength;
249     ULONG TotalSize, TotalSymLinks, UniqueIdOffset, DeviceNameOffset;
250 
251     /* If we got a symbolic link, query device */
252     if (SymbolicName)
253     {
254         Status = QueryDeviceInformation(SymbolicName,
255                                         &DeviceName,
256                                         NULL, NULL,
257                                         NULL, NULL,
258                                         NULL, NULL);
259         if (!NT_SUCCESS(Status))
260         {
261             return Status;
262         }
263     }
264 
265     /* Browse all the links to count number of links & size used */
266     TotalSize = 0;
267     TotalSymLinks = 0;
268     for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
269          DeviceEntry != &(DeviceExtension->DeviceListHead);
270          DeviceEntry = DeviceEntry->Flink)
271     {
272         DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
273 
274         /* If we were given an unique ID, it has to match */
275         if (UniqueId)
276         {
277             if (UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
278             {
279                 continue;
280             }
281 
282             if (RtlCompareMemory(UniqueId->UniqueId,
283                                  DeviceInformation->UniqueId->UniqueId,
284                                  UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
285             {
286                 continue;
287             }
288         }
289         /* Or, if we had a symlink, it has to match */
290         else if (SymbolicName)
291         {
292             if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
293             {
294                 continue;
295             }
296         }
297 
298         /* Once here, it matched, save device name & unique ID size */
299         TotalSize += DeviceInformation->DeviceName.Length + DeviceInformation->UniqueId->UniqueIdLength;
300 
301         /* And count number of symlinks (and their size) */
302         for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
303              SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
304              SymlinksEntry = SymlinksEntry->Flink)
305         {
306             SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
307 
308             TotalSize += SymlinkInformation->Name.Length;
309             TotalSymLinks++;
310         }
311 
312         /* We had a specific item to find
313          * if we reach that point, we found it, no need to continue
314          */
315         if (UniqueId || SymbolicName)
316         {
317             break;
318         }
319     }
320 
321     /* If we were looking for specific item, ensure we found it */
322     if (UniqueId || SymbolicName)
323     {
324         if (DeviceEntry == &(DeviceExtension->DeviceListHead))
325         {
326             if (SymbolicName)
327             {
328                 FreePool(DeviceName.Buffer);
329             }
330 
331             return STATUS_INVALID_PARAMETER;
332         }
333     }
334 
335     /* Now, ensure output buffer can hold everything */
336     Stack = IoGetCurrentIrpStackLocation(Irp);
337     MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
338     RtlZeroMemory(MountPoints, Stack->Parameters.DeviceIoControl.OutputBufferLength);
339 
340     /* Ensure we set output to let user reallocate! */
341     MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalSymLinks * sizeof(MOUNTMGR_MOUNT_POINT) + TotalSize;
342     MountPoints->NumberOfMountPoints = TotalSymLinks;
343     Irp->IoStatus.Information = MountPoints->Size;
344 
345     if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
346     {
347         Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS);
348 
349         if (SymbolicName)
350         {
351             FreePool(DeviceName.Buffer);
352         }
353 
354         return STATUS_BUFFER_OVERFLOW;
355     }
356 
357     /* Now, start putting mount points */
358     TotalSize = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalSymLinks * sizeof(MOUNTMGR_MOUNT_POINT);
359     TotalSymLinks = 0;
360     for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
361          DeviceEntry != &(DeviceExtension->DeviceListHead);
362          DeviceEntry = DeviceEntry->Flink)
363     {
364         DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
365 
366         /* Find back correct mount point */
367         if (UniqueId)
368         {
369             if (UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
370             {
371                 continue;
372             }
373 
374             if (RtlCompareMemory(UniqueId->UniqueId,
375                                  DeviceInformation->UniqueId->UniqueId,
376                                  UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
377             {
378                 continue;
379             }
380         }
381         else if (SymbolicName)
382         {
383             if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
384             {
385                 continue;
386             }
387         }
388 
389         /* Save our information about shared data */
390         UniqueIdOffset = TotalSize;
391         UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
392         DeviceNameOffset = TotalSize + UniqueIdLength;
393         DeviceNameLength = DeviceInformation->DeviceName.Length;
394 
395         /* Initialize first symlink */
396         MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = UniqueIdOffset;
397         MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = UniqueIdLength;
398         MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset = DeviceNameOffset;
399         MountPoints->MountPoints[TotalSymLinks].DeviceNameLength = DeviceNameLength;
400 
401         /* And copy data */
402         RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + UniqueIdOffset),
403                       DeviceInformation->UniqueId->UniqueId, UniqueIdLength);
404         RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + DeviceNameOffset),
405                       DeviceInformation->DeviceName.Buffer, DeviceNameLength);
406 
407         TotalSize += DeviceInformation->UniqueId->UniqueIdLength + DeviceInformation->DeviceName.Length;
408 
409         /* Now we've got it, but all the data */
410         for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
411              SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
412              SymlinksEntry = SymlinksEntry->Flink)
413         {
414             SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
415 
416             /* First, set shared data */
417 
418             /* Only put UniqueID if online */
419             if (SymlinkInformation->Online)
420             {
421                 MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = UniqueIdOffset;
422                 MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = UniqueIdLength;
423             }
424             else
425             {
426                 MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = 0;
427                 MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = 0;
428             }
429 
430             MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset = DeviceNameOffset;
431             MountPoints->MountPoints[TotalSymLinks].DeviceNameLength = DeviceNameLength;
432 
433             /* And now, copy specific symlink info */
434             MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset = TotalSize;
435             MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
436 
437             RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset),
438                           SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
439 
440             /* Update counters */
441             TotalSymLinks++;
442             TotalSize += SymlinkInformation->Name.Length;
443         }
444 
445         if (UniqueId || SymbolicName)
446         {
447             break;
448         }
449     }
450 
451     if (SymbolicName)
452     {
453         FreePool(DeviceName.Buffer);
454     }
455 
456     return STATUS_SUCCESS;
457 }
458 
459 /*
460  * @implemented
461  */
462 NTSTATUS
463 QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension,
464                                 IN PUNICODE_STRING SymbolicName,
465                                 IN PIRP Irp)
466 {
467     NTSTATUS Status;
468     ULONG TotalLength;
469     PIO_STACK_LOCATION Stack;
470     UNICODE_STRING DeviceName;
471     PMOUNTMGR_MOUNT_POINTS MountPoints;
472     PDEVICE_INFORMATION DeviceInformation = NULL;
473     PLIST_ENTRY DeviceEntry, SymlinksEntry;
474     PSYMLINK_INFORMATION SymlinkInformation;
475 
476     /* Find device */
477     Status = QueryDeviceInformation(SymbolicName, &DeviceName,
478                                     NULL, NULL, NULL,
479                                     NULL, NULL, NULL);
480     if (NT_SUCCESS(Status))
481     {
482         /* Look for the device information */
483         for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
484              DeviceEntry != &(DeviceExtension->DeviceListHead);
485              DeviceEntry = DeviceEntry->Flink)
486         {
487             DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
488 
489             if (RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
490             {
491                 break;
492             }
493         }
494 
495         FreePool(DeviceName.Buffer);
496 
497         if (DeviceEntry == &(DeviceExtension->DeviceListHead))
498         {
499             return STATUS_INVALID_PARAMETER;
500         }
501 
502         /* Check for the link */
503         for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
504              SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
505              SymlinksEntry = SymlinksEntry->Flink)
506         {
507             SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
508 
509             if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE))
510             {
511                 break;
512             }
513         }
514 
515         if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
516         {
517             return STATUS_INVALID_PARAMETER;
518         }
519     }
520     else
521     {
522         /* Browse all the devices to try to find the one
523          * that has the given link...
524          */
525         for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
526              DeviceEntry != &(DeviceExtension->DeviceListHead);
527              DeviceEntry = DeviceEntry->Flink)
528         {
529             DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
530 
531             for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
532                  SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
533                  SymlinksEntry = SymlinksEntry->Flink)
534             {
535                 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
536 
537                 if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE))
538                 {
539                     break;
540                 }
541             }
542 
543             if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
544             {
545                 break;
546             }
547         }
548 
549         /* Even that way we didn't find, give up! */
550         if (DeviceEntry == &(DeviceExtension->DeviceListHead))
551         {
552             return STATUS_OBJECT_NAME_NOT_FOUND;
553         }
554     }
555 
556     /* Get output buffer */
557     Stack = IoGetCurrentIrpStackLocation(Irp);
558     MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
559 
560     /* Compute output length */
561     TotalLength = DeviceInformation->UniqueId->UniqueIdLength +
562                   SymlinkInformation->Name.Length + DeviceInformation->DeviceName.Length;
563 
564     /* Give length to allow reallocation */
565     MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalLength;
566     MountPoints->NumberOfMountPoints = 1;
567     Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalLength;
568 
569     if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
570     {
571         Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS);
572 
573         return STATUS_BUFFER_OVERFLOW;
574     }
575 
576     /* Write out data */
577     MountPoints->MountPoints[0].SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS);
578     MountPoints->MountPoints[0].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
579     /* If link is online write it's unique ID, otherwise, forget about it */
580     if (SymlinkInformation->Online)
581     {
582         MountPoints->MountPoints[0].UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
583                                                      SymlinkInformation->Name.Length;
584         MountPoints->MountPoints[0].UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
585     }
586     else
587     {
588         MountPoints->MountPoints[0].UniqueIdOffset = 0;
589         MountPoints->MountPoints[0].UniqueIdLength = 0;
590     }
591 
592     MountPoints->MountPoints[0].DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
593                                                    SymlinkInformation->Name.Length +
594                                                    DeviceInformation->UniqueId->UniqueIdLength;
595     MountPoints->MountPoints[0].DeviceNameLength = DeviceInformation->DeviceName.Length;
596 
597     RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].SymbolicLinkNameOffset),
598                   SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
599 
600     if (SymlinkInformation->Online)
601     {
602         RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].UniqueIdOffset),
603                       DeviceInformation->UniqueId->UniqueId, DeviceInformation->UniqueId->UniqueIdLength);
604     }
605 
606     RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].DeviceNameOffset),
607                   DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
608 
609     return STATUS_SUCCESS;
610 }
611