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)
26 /* INCLUDES *****************************************************************/
37 MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension
,
38 IN PUNICODE_STRING SymbolicLinkName
,
39 IN PUNICODE_STRING DeviceName
)
42 PLIST_ENTRY DeviceEntry
;
43 PMOUNTDEV_UNIQUE_ID UniqueId
;
44 PSYMLINK_INFORMATION SymlinkInformation
;
45 UNICODE_STRING SymLink
, TargetDeviceName
;
46 PDEVICE_INFORMATION DeviceInformation
= NULL
, DeviceInfo
;
49 Status
= QueryDeviceInformation(SymbolicLinkName
,
53 if (!NT_SUCCESS(Status
))
58 /* First of all, try to find device */
59 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
60 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
61 DeviceEntry
= DeviceEntry
->Flink
)
63 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
65 if (RtlCompareUnicodeString(&TargetDeviceName
, &(DeviceInformation
->DeviceName
), TRUE
) == 0)
71 /* Copy symbolic link name and null terminate it */
72 SymLink
.Buffer
= AllocatePool(SymbolicLinkName
->Length
+ sizeof(UNICODE_NULL
));
75 FreePool(TargetDeviceName
.Buffer
);
76 return STATUS_INSUFFICIENT_RESOURCES
;
79 RtlCopyMemory(SymLink
.Buffer
, SymbolicLinkName
->Buffer
, SymbolicLinkName
->Length
);
80 SymLink
.Buffer
[SymbolicLinkName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
81 SymLink
.Length
= SymbolicLinkName
->Length
;
82 SymLink
.MaximumLength
= SymbolicLinkName
->Length
+ sizeof(UNICODE_NULL
);
84 /* If we didn't find device */
85 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
87 /* Then, try with unique ID */
88 Status
= QueryDeviceInformation(SymbolicLinkName
,
92 if (!NT_SUCCESS(Status
))
94 FreePool(TargetDeviceName
.Buffer
);
95 FreePool(SymLink
.Buffer
);
99 /* Create a link to the device */
100 Status
= GlobalCreateSymbolicLink(&SymLink
, &TargetDeviceName
);
101 if (!NT_SUCCESS(Status
))
104 FreePool(TargetDeviceName
.Buffer
);
105 FreePool(SymLink
.Buffer
);
109 /* If caller provided driver letter, delete it */
110 if (IsDriveLetter(&SymLink
))
112 DeleteRegistryDriveLetter(UniqueId
);
115 /* Device will be identified with its unique ID */
116 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
121 UniqueId
->UniqueIdLength
);
124 FreePool(TargetDeviceName
.Buffer
);
125 FreePool(SymLink
.Buffer
);
129 /* If call provided a driver letter whereas device already has one
130 * fail, this is not doable
132 if (IsDriveLetter(&SymLink
) && HasDriveLetter(DeviceInformation
))
134 FreePool(TargetDeviceName
.Buffer
);
135 FreePool(SymLink
.Buffer
);
136 return STATUS_INVALID_PARAMETER
;
139 /* Now, create a link */
140 Status
= GlobalCreateSymbolicLink(&SymLink
, &TargetDeviceName
);
141 FreePool(TargetDeviceName
.Buffer
);
142 if (!NT_SUCCESS(Status
))
144 FreePool(SymLink
.Buffer
);
148 /* Associate Unique ID <-> symbolic name */
149 UniqueId
= DeviceInformation
->UniqueId
;
150 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
155 UniqueId
->UniqueIdLength
);
156 if (!NT_SUCCESS(Status
))
158 GlobalDeleteSymbolicLink(&SymLink
);
159 FreePool(SymLink
.Buffer
);
163 /* Now, prepare to save the link with the device */
164 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
165 if (!SymlinkInformation
)
167 Status
= STATUS_INSUFFICIENT_RESOURCES
;
168 GlobalDeleteSymbolicLink(&SymLink
);
169 FreePool(SymLink
.Buffer
);
173 SymlinkInformation
->Name
.Length
= SymLink
.Length
;
174 SymlinkInformation
->Name
.MaximumLength
= SymLink
.Length
+ sizeof(UNICODE_NULL
);
175 SymlinkInformation
->Name
.Buffer
= AllocatePool(SymlinkInformation
->Name
.MaximumLength
);
176 if (!SymlinkInformation
->Name
.Buffer
)
178 Status
= STATUS_INSUFFICIENT_RESOURCES
;
179 FreePool(SymlinkInformation
);
180 GlobalDeleteSymbolicLink(&SymLink
);
181 FreePool(SymLink
.Buffer
);
185 /* Save the link and mark it online */
186 RtlCopyMemory(SymlinkInformation
->Name
.Buffer
, SymLink
.Buffer
, SymlinkInformation
->Name
.Length
);
187 SymlinkInformation
->Name
.Buffer
[SymlinkInformation
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
188 SymlinkInformation
->Online
= TRUE
;
189 InsertTailList(&DeviceInformation
->SymbolicLinksListHead
, &SymlinkInformation
->SymbolicLinksListEntry
);
190 SendLinkCreated(&(SymlinkInformation
->Name
));
192 /* If we have a drive letter */
193 if (IsDriveLetter(&SymLink
))
195 /* Then, delete the no drive letter entry */
196 DeleteNoDriveLetterEntry(UniqueId
);
198 /* And post online notification if asked */
199 if (!DeviceInformation
->SkipNotifications
)
201 PostOnlineNotification(DeviceExtension
, &DeviceInformation
->SymbolicName
);
205 /* If that's a volume with automatic drive letter, it's now time to resync databases */
206 if (MOUNTMGR_IS_VOLUME_NAME(&SymLink
) && DeviceExtension
->AutomaticDriveLetter
)
208 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
209 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
210 DeviceEntry
= DeviceEntry
->Flink
)
212 DeviceInfo
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
214 /* If there's one, ofc! */
215 if (!DeviceInfo
->NoDatabase
)
217 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInfo
);
223 FreePool(SymLink
.Buffer
);
224 MountMgrNotify(DeviceExtension
);
226 if (!DeviceInformation
->Volume
)
228 MountMgrNotifyNameChange(DeviceExtension
, DeviceName
, FALSE
);
238 QueryPointsFromMemory(IN PDEVICE_EXTENSION DeviceExtension
,
240 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
,
241 IN PUNICODE_STRING SymbolicName OPTIONAL
)
244 PIO_STACK_LOCATION Stack
;
245 UNICODE_STRING DeviceName
;
246 ULONG TotalSize
, TotalSymLinks
;
247 PMOUNTMGR_MOUNT_POINTS MountPoints
;
248 PDEVICE_INFORMATION DeviceInformation
;
249 PLIST_ENTRY DeviceEntry
, SymlinksEntry
;
250 PSYMLINK_INFORMATION SymlinkInformation
;
252 /* If we got a symbolic link, query device */
255 Status
= QueryDeviceInformation(SymbolicName
,
260 if (!NT_SUCCESS(Status
))
266 /* Browse all the links to count number of links & size used */
269 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
270 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
271 DeviceEntry
= DeviceEntry
->Flink
)
273 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
275 /* If we were given an unique ID, it has to match */
278 if (UniqueId
->UniqueIdLength
!= DeviceInformation
->UniqueId
->UniqueIdLength
)
283 if (RtlCompareMemory(UniqueId
->UniqueId
,
284 DeviceInformation
->UniqueId
->UniqueId
,
285 UniqueId
->UniqueIdLength
) != UniqueId
->UniqueIdLength
)
290 /* Or, if we had a symlink, it has to match */
291 else if (SymbolicName
)
293 if (!RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
299 /* Once here, it matched, save device name & unique ID size */
300 TotalSize
+= DeviceInformation
->DeviceName
.Length
+ DeviceInformation
->UniqueId
->UniqueIdLength
;
302 /* And count number of symlinks (and their size) */
303 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
304 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
305 SymlinksEntry
= SymlinksEntry
->Flink
)
307 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
309 TotalSize
+= SymlinkInformation
->Name
.Length
;
313 /* We had a specific item to find
314 * if we reach that point, we found it, no need to continue
316 if (UniqueId
|| SymbolicName
)
322 /* If we were looking for specific item, ensure we found it */
323 if (UniqueId
|| SymbolicName
)
325 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
327 if (DeviceName
.Buffer
)
329 FreePool(DeviceName
.Buffer
);
332 return STATUS_INVALID_PARAMETER
;
336 /* Now, ensure output buffer can hold everything */
337 Stack
= IoGetNextIrpStackLocation(Irp
);
338 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
340 /* Ensure we set output to let user reallocate! */
341 MountPoints
->Size
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalSize
;
342 MountPoints
->NumberOfMountPoints
= TotalSymLinks
;
344 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
346 return STATUS_BUFFER_OVERFLOW
;
349 /* Now, start putting mount points */
352 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
353 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
354 DeviceEntry
= DeviceEntry
->Flink
)
356 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
358 /* Find back correct mount point */
361 if (!UniqueId
->UniqueIdLength
!= DeviceInformation
->UniqueId
->UniqueIdLength
)
366 if (RtlCompareMemory(UniqueId
->UniqueId
,
367 DeviceInformation
->UniqueId
->UniqueId
,
368 UniqueId
->UniqueIdLength
) != UniqueId
->UniqueIdLength
)
373 else if (SymbolicName
)
375 if (!RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
))
381 /* Now we've got it, but all the data */
382 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
383 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
384 SymlinksEntry
= SymlinksEntry
->Flink
)
386 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
389 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
391 MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
392 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
393 SymlinkInformation
->Name
.Length
+
395 MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
396 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
397 SymlinkInformation
->Name
.Length
+
398 DeviceInformation
->UniqueId
->UniqueIdLength
+
400 MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
402 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].SymbolicLinkNameOffset
),
403 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
404 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].UniqueIdOffset
),
405 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
406 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[TotalSymLinks
].DeviceNameOffset
),
407 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
409 /* Update counters */
411 TotalSize
+= SymlinkInformation
->Name
.Length
+ DeviceInformation
->UniqueId
->UniqueIdLength
+
412 DeviceInformation
->DeviceName
.Length
;
415 if (UniqueId
|| SymbolicName
)
421 return STATUS_SUCCESS
;
428 QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension
,
429 IN PUNICODE_STRING SymbolicName
,
434 PIO_STACK_LOCATION Stack
;
435 UNICODE_STRING DeviceName
;
436 PMOUNTMGR_MOUNT_POINTS MountPoints
;
437 PDEVICE_INFORMATION DeviceInformation
= NULL
;
438 PLIST_ENTRY DeviceEntry
, SymlinksEntry
;
439 PSYMLINK_INFORMATION SymlinkInformation
;
442 Status
= QueryDeviceInformation(SymbolicName
, &DeviceName
,
445 if (NT_SUCCESS(Status
))
447 /* Look for the device information */
448 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
449 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
450 DeviceEntry
= DeviceEntry
->Flink
)
452 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
454 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
) == 0)
460 FreePool(DeviceName
.Buffer
);
462 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
464 return STATUS_INVALID_PARAMETER
;
467 /* Check for the link */
468 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
469 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
470 SymlinksEntry
= DeviceEntry
->Flink
)
472 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
474 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
) == 0)
480 if (SymlinksEntry
== &(DeviceInformation
->SymbolicLinksListHead
))
482 return STATUS_INVALID_PARAMETER
;
487 /* Browse all the devices to try to find the one
488 * that has the given link...
490 for (DeviceEntry
= DeviceExtension
->DeviceListHead
.Flink
;
491 DeviceEntry
!= &(DeviceExtension
->DeviceListHead
);
492 DeviceEntry
= DeviceEntry
->Flink
)
494 DeviceInformation
= CONTAINING_RECORD(DeviceEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
496 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
497 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
498 SymlinksEntry
= SymlinksEntry
->Flink
)
500 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
502 if (RtlEqualUnicodeString(SymbolicName
, &SymlinkInformation
->Name
, TRUE
) == 0)
508 if (SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
))
514 /* Even that way we didn't find, give up! */
515 if (DeviceEntry
== &(DeviceExtension
->DeviceListHead
))
517 return STATUS_OBJECT_NAME_NOT_FOUND
;
521 /* Get output buffer */
522 Stack
= IoGetNextIrpStackLocation(Irp
);
523 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
525 /* Compute output length */
526 TotalLength
= DeviceInformation
->UniqueId
->UniqueIdLength
+
527 SymlinkInformation
->Name
.Length
+ DeviceInformation
->DeviceName
.Length
;
529 /* Give length to allow reallocation */
530 MountPoints
->Size
= sizeof(MOUNTMGR_MOUNT_POINTS
) + TotalLength
;
531 MountPoints
->NumberOfMountPoints
= 1;
533 if (MountPoints
->Size
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
535 return STATUS_BUFFER_OVERFLOW
;
539 MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
);
540 MountPoints
->MountPoints
[0].SymbolicLinkNameLength
= SymlinkInformation
->Name
.Length
;
541 /* If link is online write it's unique ID, otherwise, forget about it */
542 if (SymlinkInformation
->Online
)
544 MountPoints
->MountPoints
[0].UniqueIdOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
545 SymlinkInformation
->Name
.Length
;
546 MountPoints
->MountPoints
[0].UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
550 MountPoints
->MountPoints
[0].UniqueIdOffset
= 0;
551 MountPoints
->MountPoints
[0].UniqueIdLength
= 0;
554 MountPoints
->MountPoints
[0].DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINTS
) +
555 SymlinkInformation
->Name
.Length
+
556 DeviceInformation
->UniqueId
->UniqueIdLength
;
557 MountPoints
->MountPoints
[0].DeviceNameLength
= DeviceInformation
->DeviceName
.Length
;
559 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].SymbolicLinkNameOffset
),
560 SymlinkInformation
->Name
.Buffer
, SymlinkInformation
->Name
.Length
);
562 if (SymlinkInformation
->Online
)
564 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].UniqueIdOffset
),
565 DeviceInformation
->UniqueId
->UniqueId
, DeviceInformation
->UniqueId
->UniqueIdLength
);
568 RtlCopyMemory((PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[0].DeviceNameOffset
),
569 DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
571 return STATUS_SUCCESS
;