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 (RtlEqualUnicodeString(&TargetDeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
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
= IoGetCurrentIrpStackLocation(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
;
341 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalSize
;
343 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
345 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_MOUNT_POINTS
);
349 FreePool(DeviceName
.Buffer
);
352 return STATUS_BUFFER_OVERFLOW
;
355 /* Now, start putting mount points */
358 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
359 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
360 DeviceEntry
= DeviceEntry
->Flink
)
362 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
364 /* Find back correct mount point */
367 if (UniqueId
->UniqueIdLength
!= DeviceInformation
->UniqueId
->UniqueIdLength
)
372 if (RtlCompareMemory(UniqueId
->UniqueId
,
373 DeviceInformation
->UniqueId
->UniqueId
,
374 UniqueId
->UniqueIdLength
) != UniqueId
->UniqueIdLength
)
379 else if (SymbolicName
)
381 if (!RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
387 /* Now we've got it, but all the data */
388 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
389 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
390 SymlinksEntry
= SymlinksEntry
->Flink
)
392 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
395 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
397 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
398 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
399 SymlinkInformation
->Name
.Length
+
401 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
402 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
403 SymlinkInformation
->Name
.Length
+
404 DeviceInformation
->UniqueId
->UniqueIdLength
+
406 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
408 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
),
409 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
410 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
),
411 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
412 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
),
413 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
415 /* Update counters */
417 TotalSize
+= SymlinkInformation
->Name
.Length
+ DeviceInformation
->UniqueId
->UniqueIdLength
+
418 DeviceInformation
->DeviceName
.Length
;
421 if (UniqueId
|| SymbolicName
)
429 FreePool(DeviceName
.Buffer
);
432 return STATUS_SUCCESS
;
439 QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension
,
440 IN PUNICODE_STRING SymbolicName
,
445 PIO_STACK_LOCATION Stack
;
446 UNICODE_STRING DeviceName
;
447 PMOUNTMGR_MOUNT_POINTS MountPoints
;
448 PDEVICE_INFORMATION DeviceInformation
= NULL
;
449 PLIST_ENTRY DeviceEntry
, SymlinksEntry
;
450 PSYMLINK_INFORMATION SymlinkInformation
;
453 Status
= QueryDeviceInformation(SymbolicName
, &DeviceName
,
456 if (NT_SUCCESS(Status
))
458 /* Look for the device information */
459 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
460 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
461 DeviceEntry
= DeviceEntry
->Flink
)
463 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
465 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
471 FreePool(DeviceName
.Buffer
);
473 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
475 return STATUS_INVALID_PARAMETER
;
478 /* Check for the link */
479 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
480 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
481 SymlinksEntry
= SymlinksEntry
->Flink
)
483 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
485 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
))
491 if (SymlinksEntry
== &(DeviceInformation
->SymbolicLinksListHead
))
493 return STATUS_INVALID_PARAMETER
;
498 /* Browse all the devices to try to find the one
499 * that has the given link...
501 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
502 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
503 DeviceEntry
= DeviceEntry
->Flink
)
505 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
507 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
508 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
509 SymlinksEntry
= SymlinksEntry
->Flink
)
511 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
513 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
))
519 if (SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
))
525 /* Even that way we didn't find, give up! */
526 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
528 return STATUS_OBJECT_NAME_NOT_FOUND
;
532 /* Get output buffer */
533 Stack
= IoGetCurrentIrpStackLocation(Irp
);
534 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
536 /* Compute output length */
537 TotalLength
= DeviceInformation
->UniqueId
->UniqueIdLength
+
538 SymlinkInformation
->Name
.Length
+ DeviceInformation
->DeviceName
.Length
;
540 /* Give length to allow reallocation */
541 MountPoints
->Size
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalLength
;
542 MountPoints
->NumberOfMountPoints
= 1;
543 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalLength
;
545 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
547 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_MOUNT_POINTS
);
549 return STATUS_BUFFER_OVERFLOW
;
553 MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
);
554 MountPoints
->MountPoints
[0].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
555 /* If link is online write it's unique ID, otherwise, forget about it */
556 if (SymlinkInformation
->Online
)
558 MountPoints
->MountPoints
[0].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
559 SymlinkInformation
->Name
.Length
;
560 MountPoints
->MountPoints
[0].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
564 MountPoints
->MountPoints
[0].UniqueIdOffset
= 0;
565 MountPoints
->MountPoints
[0].UniqueIdLength
= 0;
568 MountPoints
->MountPoints
[0].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
569 SymlinkInformation
->Name
.Length
+
570 DeviceInformation
->UniqueId
->UniqueIdLength
;
571 MountPoints
->MountPoints
[0].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
573 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
),
574 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
576 if (SymlinkInformation
->Online
)
578 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].UniqueIdOffset
),
579 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
582 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].DeviceNameOffset
),
583 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
585 return STATUS_SUCCESS
;