3 * Copyright (C) 2011-2012 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/point.c
22 * PURPOSE: Mount Manager - Mount points
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
35 MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension
,
36 IN PUNICODE_STRING SymbolicLinkName
,
37 IN PUNICODE_STRING DeviceName
)
40 PLIST_ENTRY DeviceEntry
;
41 PMOUNTDEV_UNIQUE_ID UniqueId
;
42 PSYMLINK_INFORMATION SymlinkInformation
;
43 UNICODE_STRING SymLink
, TargetDeviceName
;
44 PDEVICE_INFORMATION DeviceInformation
= NULL
, DeviceInfo
;
47 Status
= QueryDeviceInformation(SymbolicLinkName
,
51 if (!NT_SUCCESS(Status
))
56 /* First of all, try to find device */
57 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
58 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
59 DeviceEntry
= DeviceEntry
->Flink
)
61 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
63 if (RtlCompareUnicodeString(&TargetDeviceName
, &(DeviceInformation
->DeviceName
), TRUE
) == 0)
69 /* Copy symbolic link name and null terminate it */
70 SymLink
.Buffer
= AllocatePool(SymbolicLinkName
->Length
+ sizeof(UNICODE_NULL
));
73 FreePool(TargetDeviceName
.Buffer
);
74 return STATUS_INSUFFICIENT_RESOURCES
;
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
);
82 /* If we didn't find device */
83 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
85 /* Then, try with unique ID */
86 Status
= QueryDeviceInformation(SymbolicLinkName
,
90 if (!NT_SUCCESS(Status
))
92 FreePool(TargetDeviceName
.Buffer
);
93 FreePool(SymLink
.Buffer
);
97 /* Create a link to the device */
98 Status
= GlobalCreateSymbolicLink(&SymLink
, &TargetDeviceName
);
99 if (!NT_SUCCESS(Status
))
102 FreePool(TargetDeviceName
.Buffer
);
103 FreePool(SymLink
.Buffer
);
107 /* If caller provided driver letter, delete it */
108 if (IsDriveLetter(&SymLink
))
110 DeleteRegistryDriveLetter(UniqueId
);
113 /* Device will be identified with its unique ID */
114 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
119 UniqueId
->UniqueIdLength
);
122 FreePool(TargetDeviceName
.Buffer
);
123 FreePool(SymLink
.Buffer
);
127 /* If call provided a driver letter whereas device already has one
128 * fail, this is not doable
130 if (IsDriveLetter(&SymLink
) && HasDriveLetter(DeviceInformation
))
132 FreePool(TargetDeviceName
.Buffer
);
133 FreePool(SymLink
.Buffer
);
134 return STATUS_INVALID_PARAMETER
;
137 /* Now, create a link */
138 Status
= GlobalCreateSymbolicLink(&SymLink
, &TargetDeviceName
);
139 FreePool(TargetDeviceName
.Buffer
);
140 if (!NT_SUCCESS(Status
))
142 FreePool(SymLink
.Buffer
);
146 /* Associate Unique ID <-> symbolic name */
147 UniqueId
= DeviceInformation
->UniqueId
;
148 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
153 UniqueId
->UniqueIdLength
);
154 if (!NT_SUCCESS(Status
))
156 GlobalDeleteSymbolicLink(&SymLink
);
157 FreePool(SymLink
.Buffer
);
161 /* Now, prepare to save the link with the device */
162 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
163 if (!SymlinkInformation
)
165 Status
= STATUS_INSUFFICIENT_RESOURCES
;
166 GlobalDeleteSymbolicLink(&SymLink
);
167 FreePool(SymLink
.Buffer
);
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
)
176 Status
= STATUS_INSUFFICIENT_RESOURCES
;
177 FreePool(SymlinkInformation
);
178 GlobalDeleteSymbolicLink(&SymLink
);
179 FreePool(SymLink
.Buffer
);
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
));
190 /* If we have a drive letter */
191 if (IsDriveLetter(&SymLink
))
193 /* Then, delete the no drive letter entry */
194 DeleteNoDriveLetterEntry(UniqueId
);
196 /* And post online notification if asked */
197 if (!DeviceInformation
->SkipNotifications
)
199 PostOnlineNotification(DeviceExtension
, &DeviceInformation
->SymbolicName
);
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
)
206 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
207 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
208 DeviceEntry
= DeviceEntry
->Flink
)
210 DeviceInfo
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
212 /* If there's one, ofc! */
213 if (!DeviceInfo
->NoDatabase
)
215 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInfo
);
221 FreePool(SymLink
.Buffer
);
222 MountMgrNotify(DeviceExtension
);
224 if (!DeviceInformation
->ManuallyRegistered
)
226 MountMgrNotifyNameChange(DeviceExtension
, DeviceName
, FALSE
);
236 QueryPointsFromMemory(IN PDEVICE_EXTENSION DeviceExtension
,
238 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
,
239 IN PUNICODE_STRING SymbolicName OPTIONAL
)
242 PIO_STACK_LOCATION Stack
;
243 UNICODE_STRING DeviceName
;
244 ULONG TotalSize
, TotalSymLinks
;
245 PMOUNTMGR_MOUNT_POINTS MountPoints
;
246 PDEVICE_INFORMATION DeviceInformation
;
247 PLIST_ENTRY DeviceEntry
, SymlinksEntry
;
248 PSYMLINK_INFORMATION SymlinkInformation
;
250 /* If we got a symbolic link, query device */
253 Status
= QueryDeviceInformation(SymbolicName
,
258 if (!NT_SUCCESS(Status
))
264 /* Browse all the links to count number of links & size used */
267 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
268 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
269 DeviceEntry
= DeviceEntry
->Flink
)
271 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
273 /* If we were given an unique ID, it has to match */
276 if (UniqueId
->UniqueIdLength
!= DeviceInformation
->UniqueId
->UniqueIdLength
)
281 if (RtlCompareMemory(UniqueId
->UniqueId
,
282 DeviceInformation
->UniqueId
->UniqueId
,
283 UniqueId
->UniqueIdLength
) != UniqueId
->UniqueIdLength
)
288 /* Or, if we had a symlink, it has to match */
289 else if (SymbolicName
)
291 if (!RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
297 /* Once here, it matched, save device name & unique ID size */
298 TotalSize
+= DeviceInformation
->DeviceName
.Length
+ DeviceInformation
->UniqueId
->UniqueIdLength
;
300 /* And count number of symlinks (and their size) */
301 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
302 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
303 SymlinksEntry
= SymlinksEntry
->Flink
)
305 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
307 TotalSize
+= SymlinkInformation
->Name
.Length
;
311 /* We had a specific item to find
312 * if we reach that point, we found it, no need to continue
314 if (UniqueId
|| SymbolicName
)
320 /* If we were looking for specific item, ensure we found it */
321 if (UniqueId
|| SymbolicName
)
323 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
327 FreePool(DeviceName
.Buffer
);
330 return STATUS_INVALID_PARAMETER
;
334 /* Now, ensure output buffer can hold everything */
335 Stack
= IoGetNextIrpStackLocation(Irp
);
336 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
338 /* Ensure we set output to let user reallocate! */
339 MountPoints
->Size
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalSize
;
340 MountPoints
->NumberOfMountPoints
= TotalSymLinks
;
342 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
344 return STATUS_BUFFER_OVERFLOW
;
347 /* Now, start putting mount points */
350 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
351 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
352 DeviceEntry
= DeviceEntry
->Flink
)
354 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
356 /* Find back correct mount point */
359 if (UniqueId
->UniqueIdLength
!= DeviceInformation
->UniqueId
->UniqueIdLength
)
364 if (RtlCompareMemory(UniqueId
->UniqueId
,
365 DeviceInformation
->UniqueId
->UniqueId
,
366 UniqueId
->UniqueIdLength
) != UniqueId
->UniqueIdLength
)
371 else if (SymbolicName
)
373 if (!RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
379 /* Now we've got it, but all the data */
380 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
381 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
382 SymlinksEntry
= SymlinksEntry
->Flink
)
384 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
387 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
389 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
390 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
391 SymlinkInformation
->Name
.Length
+
393 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
394 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
395 SymlinkInformation
->Name
.Length
+
396 DeviceInformation
->UniqueId
->UniqueIdLength
+
398 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
400 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
),
401 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
402 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
),
403 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
404 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
),
405 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
407 /* Update counters */
409 TotalSize
+= SymlinkInformation
->Name
.Length
+ DeviceInformation
->UniqueId
->UniqueIdLength
+
410 DeviceInformation
->DeviceName
.Length
;
413 if (UniqueId
|| SymbolicName
)
419 return STATUS_SUCCESS
;
426 QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension
,
427 IN PUNICODE_STRING SymbolicName
,
432 PIO_STACK_LOCATION Stack
;
433 UNICODE_STRING DeviceName
;
434 PMOUNTMGR_MOUNT_POINTS MountPoints
;
435 PDEVICE_INFORMATION DeviceInformation
= NULL
;
436 PLIST_ENTRY DeviceEntry
, SymlinksEntry
;
437 PSYMLINK_INFORMATION SymlinkInformation
;
440 Status
= QueryDeviceInformation(SymbolicName
, &DeviceName
,
443 if (NT_SUCCESS(Status
))
445 /* Look for the device information */
446 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
447 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
448 DeviceEntry
= DeviceEntry
->Flink
)
450 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
452 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
) == 0)
458 FreePool(DeviceName
.Buffer
);
460 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
462 return STATUS_INVALID_PARAMETER
;
465 /* Check for the link */
466 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
467 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
468 SymlinksEntry
= DeviceEntry
->Flink
)
470 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
472 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
) == 0)
478 if (SymlinksEntry
== &(DeviceInformation
->SymbolicLinksListHead
))
480 return STATUS_INVALID_PARAMETER
;
485 /* Browse all the devices to try to find the one
486 * that has the given link...
488 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
489 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
490 DeviceEntry
= DeviceEntry
->Flink
)
492 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
494 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
495 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
496 SymlinksEntry
= SymlinksEntry
->Flink
)
498 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
500 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
) == 0)
506 if (SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
))
512 /* Even that way we didn't find, give up! */
513 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
515 return STATUS_OBJECT_NAME_NOT_FOUND
;
519 /* Get output buffer */
520 Stack
= IoGetNextIrpStackLocation(Irp
);
521 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
523 /* Compute output length */
524 TotalLength
= DeviceInformation
->UniqueId
->UniqueIdLength
+
525 SymlinkInformation
->Name
.Length
+ DeviceInformation
->DeviceName
.Length
;
527 /* Give length to allow reallocation */
528 MountPoints
->Size
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalLength
;
529 MountPoints
->NumberOfMountPoints
= 1;
531 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
533 return STATUS_BUFFER_OVERFLOW
;
537 MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
);
538 MountPoints
->MountPoints
[0].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
539 /* If link is online write it's unique ID, otherwise, forget about it */
540 if (SymlinkInformation
->Online
)
542 MountPoints
->MountPoints
[0].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
543 SymlinkInformation
->Name
.Length
;
544 MountPoints
->MountPoints
[0].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
548 MountPoints
->MountPoints
[0].UniqueIdOffset
= 0;
549 MountPoints
->MountPoints
[0].UniqueIdLength
= 0;
552 MountPoints
->MountPoints
[0].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
553 SymlinkInformation
->Name
.Length
+
554 DeviceInformation
->UniqueId
->UniqueIdLength
;
555 MountPoints
->MountPoints
[0].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
557 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
),
558 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
560 if (SymlinkInformation
->Online
)
562 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].UniqueIdOffset
),
563 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
566 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].DeviceNameOffset
),
567 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
569 return STATUS_SUCCESS
;