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