[SHELL32] Fix Control_RunDLLW (#5400)
[reactos.git] / ntoskrnl / io / iomgr / arcname.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/arcname.c
5 * PURPOSE: ARC Path Initialization Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
20 PCHAR IoLoaderArcBootDeviceName;
21
22 /* FUNCTIONS *****************************************************************/
23
24 CODE_SEG("INIT")
25 NTSTATUS
26 NTAPI
27 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
28
29 CODE_SEG("INIT")
30 NTSTATUS
31 NTAPI
32 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
33 IN BOOLEAN SingleDisk,
34 OUT PBOOLEAN FoundBoot);
35
36 CODE_SEG("INIT")
37 NTSTATUS
38 NTAPI
39 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
40 {
41 SIZE_T Length;
42 NTSTATUS Status;
43 CHAR Buffer[128];
44 BOOLEAN SingleDisk;
45 BOOLEAN FoundBoot = FALSE;
46 UNICODE_STRING SystemDevice, LoaderPathNameW, BootDeviceName;
47 PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
48 ANSI_STRING ArcSystemString, ArcString, LanmanRedirector, LoaderPathNameA;
49
50 /* Check if we only have one disk on the machine */
51 SingleDisk = (ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
52 &ArcDiskInfo->DiskSignatureListHead);
53
54 /* Create the global HAL partition name */
55 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
56 RtlInitAnsiString(&ArcString, Buffer);
57 Status = RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
58 if (!NT_SUCCESS(Status))
59 return Status;
60
61 /* Create the global system partition name */
62 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
63 RtlInitAnsiString(&ArcString, Buffer);
64 Status = RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
65 if (!NT_SUCCESS(Status))
66 return Status;
67
68 /* Allocate memory for the string */
69 Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
70 IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
71 Length,
72 TAG_IO);
73 if (IoLoaderArcBootDeviceName)
74 {
75 /* Copy the name */
76 RtlCopyMemory(IoLoaderArcBootDeviceName,
77 LoaderBlock->ArcBootDeviceName,
78 Length);
79 }
80
81 /* Check if we only found a disk, but we're booting from CD-ROM */
82 if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
83 {
84 /* Then disable single-disk mode, since there's a CD drive out there */
85 SingleDisk = FALSE;
86 }
87
88 /* Build the boot strings */
89 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
90
91 /* If we are doing remote booting */
92 if (IoRemoteBootClient)
93 {
94 /* Yes, we have found boot device */
95 FoundBoot = TRUE;
96
97 /* Get NT device name */
98 RtlInitAnsiString(&LanmanRedirector, "\\Device\\LanmanRedirector");
99 Status = RtlAnsiStringToUnicodeString(&SystemDevice, &LanmanRedirector, TRUE);
100 if (!NT_SUCCESS(Status))
101 {
102 return Status;
103 }
104
105 /* Get ARC booting device name (in net(0) something) */
106 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
107 RtlInitAnsiString(&ArcString, Buffer);
108 Status = RtlAnsiStringToUnicodeString(&BootDeviceName, &ArcString, TRUE);
109 if (NT_SUCCESS(Status))
110 {
111 /* Map ARC to NT name */
112 IoAssignArcName(&BootDeviceName, &SystemDevice);
113 RtlFreeUnicodeString(&BootDeviceName);
114
115 /* Now, get loader path name */
116 RtlInitAnsiString(&LoaderPathNameA, LoaderBlock->NtHalPathName);
117 Status = RtlAnsiStringToUnicodeString(&LoaderPathNameW, &LoaderPathNameA, TRUE);
118 if (!NT_SUCCESS(Status))
119 {
120 RtlFreeUnicodeString(&SystemDevice);
121 return Status;
122 }
123
124 /* And set it has system partition */
125 IopStoreSystemPartitionInformation(&SystemDevice, &LoaderPathNameW);
126 }
127
128 RtlFreeUnicodeString(&SystemDevice);
129
130 /* Don't quit here, even if everything went fine!
131 * We need IopCreateArcNamesDisk to properly map
132 * devices with symlinks.
133 * It will return success if the mapping process went fine
134 * even if it didn't find boot device.
135 * It won't reset boot device finding status as well.
136 */
137 }
138
139 /* Loop every disk and try to find boot disk */
140 Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot);
141 /* If it succeeded but we didn't find boot device, try to browse Cds */
142 if (NT_SUCCESS(Status) && !FoundBoot)
143 {
144 Status = IopCreateArcNamesCd(LoaderBlock);
145 }
146
147 /* Return success */
148 return Status;
149 }
150
151 CODE_SEG("INIT")
152 NTSTATUS
153 NTAPI
154 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
155 {
156 PIRP Irp;
157 KEVENT Event;
158 NTSTATUS Status;
159 PLIST_ENTRY NextEntry;
160 PFILE_OBJECT FileObject;
161 PDEVICE_OBJECT DeviceObject;
162 LARGE_INTEGER StartingOffset;
163 IO_STATUS_BLOCK IoStatusBlock;
164 PULONG PartitionBuffer = NULL;
165 CHAR Buffer[128], ArcBuffer[128];
166 BOOLEAN NotEnabledPresent = FALSE;
167 STORAGE_DEVICE_NUMBER DeviceNumber;
168 ANSI_STRING DeviceStringA, ArcNameStringA;
169 PWSTR SymbolicLinkList, lSymbolicLinkList;
170 PARC_DISK_SIGNATURE ArcDiskSignature = NULL;
171 UNICODE_STRING DeviceStringW, ArcNameStringW;
172 ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0;
173 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
174
175 /* Get all the Cds present in the system */
176 CdRomCount = IoGetConfigurationInformation()->CdRomCount;
177
178 /* Get enabled Cds and check if result matches
179 * For the record, enabled Cds (or even disk) are Cds/disks
180 * that have been successfully handled by MountMgr driver
181 * and that already own their device name. This is the "new" way
182 * to handle them, that came with NT5.
183 * Currently, Windows 2003 provides an ARC names creation based
184 * on both enabled drives and not enabled drives (lack from
185 * the driver).
186 * Given the current ReactOS state, that's good for us.
187 * To sum up, this is NOT a hack or whatsoever.
188 */
189 Status = IopFetchConfigurationInformation(&SymbolicLinkList,
190 GUID_DEVINTERFACE_CDROM,
191 CdRomCount,
192 &EnabledDisks);
193 if (!NT_SUCCESS(Status))
194 {
195 NotEnabledPresent = TRUE;
196 }
197 /* Save symbolic link list address in order to free it after */
198 lSymbolicLinkList = SymbolicLinkList;
199 /* For the moment, we won't fail */
200 Status = STATUS_SUCCESS;
201
202 /* Browse all the ARC devices trying to find the one matching boot device */
203 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
204 NextEntry != &ArcDiskInformation->DiskSignatureListHead;
205 NextEntry = NextEntry->Flink)
206 {
207 ArcDiskSignature = CONTAINING_RECORD(NextEntry,
208 ARC_DISK_SIGNATURE,
209 ListEntry);
210
211 if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0)
212 {
213 break;
214 }
215
216 ArcDiskSignature = NULL;
217 }
218
219 /* Not found... Not booting from a Cd */
220 if (!ArcDiskSignature)
221 {
222 DPRINT("Failed finding a cd that could match current boot device\n");
223 goto Cleanup;
224 }
225
226 /* Allocate needed space for reading Cd */
227 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO);
228 if (!PartitionBuffer)
229 {
230 DPRINT("Failed allocating resources!\n");
231 /* Here, we fail, BUT we return success, some Microsoft joke */
232 goto Cleanup;
233 }
234
235 /* If we have more enabled Cds, take that into account */
236 if (EnabledDisks > CdRomCount)
237 {
238 CdRomCount = EnabledDisks;
239 }
240
241 /* If we'll have to browse for none enabled Cds, fix higher count */
242 if (NotEnabledPresent && !EnabledDisks)
243 {
244 CdRomCount += 5;
245 }
246
247 /* Finally, if in spite of all that work, we still don't have Cds, leave */
248 if (!CdRomCount)
249 {
250 goto Cleanup;
251 }
252
253 /* Start browsing Cds */
254 for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++)
255 {
256 /* Check if we have an enabled disk */
257 if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
258 {
259 /* Create its device name using first symbolic link */
260 RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
261 /* Then, update symbolic links list */
262 lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
263
264 /* Get its associated device object and file object */
265 Status = IoGetDeviceObjectPointer(&DeviceStringW,
266 FILE_READ_ATTRIBUTES,
267 &FileObject,
268 &DeviceObject);
269 /* Failure? Good bye! */
270 if (!NT_SUCCESS(Status))
271 {
272 goto Cleanup;
273 }
274
275 /* Now, we'll ask the device its device number */
276 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
277 DeviceObject,
278 NULL,
279 0,
280 &DeviceNumber,
281 sizeof(DeviceNumber),
282 FALSE,
283 &Event,
284 &IoStatusBlock);
285 /* Failure? Good bye! */
286 if (!Irp)
287 {
288 /* Dereference file object before leaving */
289 ObDereferenceObject(FileObject);
290 Status = STATUS_INSUFFICIENT_RESOURCES;
291 goto Cleanup;
292 }
293
294 /* Call the driver, and wait for it if needed */
295 KeInitializeEvent(&Event, NotificationEvent, FALSE);
296 Status = IoCallDriver(DeviceObject, Irp);
297 if (Status == STATUS_PENDING)
298 {
299 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
300 Status = IoStatusBlock.Status;
301 }
302 if (!NT_SUCCESS(Status))
303 {
304 ObDereferenceObject(FileObject);
305 goto Cleanup;
306 }
307
308 /* Finally, build proper device name */
309 sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber);
310 RtlInitAnsiString(&DeviceStringA, Buffer);
311 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
312 if (!NT_SUCCESS(Status))
313 {
314 ObDereferenceObject(FileObject);
315 goto Cleanup;
316 }
317 }
318 else
319 {
320 /* Create device name for the cd */
321 sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++);
322 RtlInitAnsiString(&DeviceStringA, Buffer);
323 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
324 if (!NT_SUCCESS(Status))
325 {
326 goto Cleanup;
327 }
328
329 /* Get its device object */
330 Status = IoGetDeviceObjectPointer(&DeviceStringW,
331 FILE_READ_ATTRIBUTES,
332 &FileObject,
333 &DeviceObject);
334 if (!NT_SUCCESS(Status))
335 {
336 RtlFreeUnicodeString(&DeviceStringW);
337 goto Cleanup;
338 }
339 }
340
341 /* Initiate data for reading cd and compute checksum */
342 StartingOffset.QuadPart = 0x8000;
343 CheckSum = 0;
344 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
345 DeviceObject,
346 PartitionBuffer,
347 2048,
348 &StartingOffset,
349 &Event,
350 &IoStatusBlock);
351 if (Irp)
352 {
353 /* Call the driver, and wait for it if needed */
354 KeInitializeEvent(&Event, NotificationEvent, FALSE);
355 Status = IoCallDriver(DeviceObject, Irp);
356 if (Status == STATUS_PENDING)
357 {
358 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
359 Status = IoStatusBlock.Status;
360 }
361
362 /* If reading succeeded, compute checksum by adding data, 2048 bytes checksum */
363 if (NT_SUCCESS(Status))
364 {
365 for (i = 0; i < 2048 / sizeof(ULONG); i++)
366 {
367 CheckSum += PartitionBuffer[i];
368 }
369 }
370 }
371
372 /* Dereference file object */
373 ObDereferenceObject(FileObject);
374
375 /* If checksums are matching, we have the proper cd */
376 if (CheckSum + ArcDiskSignature->CheckSum == 0)
377 {
378 /* Create ARC name */
379 sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
380 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
381 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
382 if (NT_SUCCESS(Status))
383 {
384 /* Create symbolic link */
385 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
386 RtlFreeUnicodeString(&ArcNameStringW);
387 DPRINT("Boot device found\n");
388 }
389
390 /* And quit, whatever happens */
391 RtlFreeUnicodeString(&DeviceStringW);
392 goto Cleanup;
393 }
394
395 /* Free string before trying another disk */
396 RtlFreeUnicodeString(&DeviceStringW);
397 }
398
399 Cleanup:
400 if (PartitionBuffer)
401 {
402 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
403 }
404
405 if (SymbolicLinkList)
406 {
407 ExFreePool(SymbolicLinkList);
408 }
409
410 return Status;
411 }
412
413 CODE_SEG("INIT")
414 NTSTATUS
415 NTAPI
416 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
417 IN BOOLEAN SingleDisk,
418 OUT PBOOLEAN FoundBoot)
419 {
420 PIRP Irp;
421 PVOID Data;
422 KEVENT Event;
423 NTSTATUS Status;
424 PLIST_ENTRY NextEntry;
425 PFILE_OBJECT FileObject;
426 DISK_GEOMETRY DiskGeometry;
427 PDEVICE_OBJECT DeviceObject;
428 LARGE_INTEGER StartingOffset;
429 PULONG PartitionBuffer = NULL;
430 IO_STATUS_BLOCK IoStatusBlock;
431 CHAR Buffer[128], ArcBuffer[128];
432 BOOLEAN NotEnabledPresent = FALSE;
433 STORAGE_DEVICE_NUMBER DeviceNumber;
434 PARC_DISK_SIGNATURE ArcDiskSignature;
435 PWSTR SymbolicLinkList, lSymbolicLinkList;
436 PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
437 UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW;
438 ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0;
439 PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
440 ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA;
441
442 /* Initialise device number */
443 DeviceNumber.DeviceNumber = ULONG_MAX;
444 /* Get all the disks present in the system */
445 DiskCount = IoGetConfigurationInformation()->DiskCount;
446
447 /* Get enabled disks and check if result matches */
448 Status = IopFetchConfigurationInformation(&SymbolicLinkList,
449 GUID_DEVINTERFACE_DISK,
450 DiskCount,
451 &EnabledDisks);
452 if (!NT_SUCCESS(Status))
453 {
454 NotEnabledPresent = TRUE;
455 }
456
457 /* Save symbolic link list address in order to free it after */
458 lSymbolicLinkList = SymbolicLinkList;
459
460 /* Build the boot strings */
461 RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
462 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
463
464 /* If we have more enabled disks, take that into account */
465 if (EnabledDisks > DiskCount)
466 {
467 DiskCount = EnabledDisks;
468 }
469
470 /* If we'll have to browse for none enabled disks, fix higher count */
471 if (NotEnabledPresent && !EnabledDisks)
472 {
473 DiskCount += 20;
474 }
475
476 /* Finally, if in spite of all that work, we still don't have disks, leave */
477 if (!DiskCount)
478 {
479 goto Cleanup;
480 }
481
482 /* Start browsing disks */
483 for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
484 {
485 ASSERT(DriveLayout == NULL);
486
487 /* Check if we have an enabled disk */
488 if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
489 {
490 /* Create its device name using first symbolic link */
491 RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
492 /* Then, update symbolic links list */
493 lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
494
495 /* Get its associated device object and file object */
496 Status = IoGetDeviceObjectPointer(&DeviceStringW,
497 FILE_READ_ATTRIBUTES,
498 &FileObject,
499 &DeviceObject);
500 if (NT_SUCCESS(Status))
501 {
502 /* Now, we'll ask the device its device number */
503 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
504 DeviceObject,
505 NULL,
506 0,
507 &DeviceNumber,
508 sizeof(DeviceNumber),
509 FALSE,
510 &Event,
511 &IoStatusBlock);
512 /* Missing resources is a shame... No need to go farther */
513 if (!Irp)
514 {
515 ObDereferenceObject(FileObject);
516 Status = STATUS_INSUFFICIENT_RESOURCES;
517 goto Cleanup;
518 }
519
520 /* Call the driver, and wait for it if needed */
521 KeInitializeEvent(&Event, NotificationEvent, FALSE);
522 Status = IoCallDriver(DeviceObject, Irp);
523 if (Status == STATUS_PENDING)
524 {
525 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
526 Status = IoStatusBlock.Status;
527 }
528
529 /* If we didn't get the appriopriate data, just skip that disk */
530 if (!NT_SUCCESS(Status))
531 {
532 ObDereferenceObject(FileObject);
533 continue;
534 }
535 }
536
537 /* End of enabled disks enumeration */
538 if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL)
539 {
540 /* No enabled disk worked, reset field */
541 if (DeviceNumber.DeviceNumber == ULONG_MAX)
542 {
543 DeviceNumber.DeviceNumber = 0;
544 }
545
546 /* Update disk number to enable the following not enabled disks */
547 if (DeviceNumber.DeviceNumber > DiskNumber)
548 {
549 DiskNumber = DeviceNumber.DeviceNumber;
550 }
551
552 /* Increase a bit more */
553 DiskCount = DiskNumber + 20;
554 }
555 }
556 else
557 {
558 /* Create device name for the disk */
559 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
560 RtlInitAnsiString(&DeviceStringA, Buffer);
561 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
562 if (!NT_SUCCESS(Status))
563 {
564 goto Cleanup;
565 }
566
567 /* Get its device object */
568 Status = IoGetDeviceObjectPointer(&DeviceStringW,
569 FILE_READ_ATTRIBUTES,
570 &FileObject,
571 &DeviceObject);
572
573 RtlFreeUnicodeString(&DeviceStringW);
574 /* This is a security measure, to ensure DiskNumber will be used */
575 DeviceNumber.DeviceNumber = ULONG_MAX;
576 }
577
578 /* Something failed somewhere earlier, just skip the disk */
579 if (!NT_SUCCESS(Status))
580 {
581 continue;
582 }
583
584 /* Let's ask the disk for its geometry */
585 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
586 DeviceObject,
587 NULL,
588 0,
589 &DiskGeometry,
590 sizeof(DiskGeometry),
591 FALSE,
592 &Event,
593 &IoStatusBlock);
594 /* Missing resources is a shame... No need to go farther */
595 if (!Irp)
596 {
597 ObDereferenceObject(FileObject);
598 Status = STATUS_INSUFFICIENT_RESOURCES;
599 goto Cleanup;
600 }
601
602 /* Call the driver, and wait for it if needed */
603 KeInitializeEvent(&Event, NotificationEvent, FALSE);
604 Status = IoCallDriver(DeviceObject, Irp);
605 if (Status == STATUS_PENDING)
606 {
607 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
608 Status = IoStatusBlock.Status;
609 }
610 /* Failure, skip disk */
611 if (!NT_SUCCESS(Status))
612 {
613 ObDereferenceObject(FileObject);
614 continue;
615 }
616
617 /* Read the partition table */
618 Status = IoReadPartitionTableEx(DeviceObject,
619 &DriveLayout);
620 if (!NT_SUCCESS(Status))
621 {
622 ObDereferenceObject(FileObject);
623 continue;
624 }
625
626 /* Ensure we have at least 512 bytes per sector */
627 if (DiskGeometry.BytesPerSector < 512)
628 {
629 DiskGeometry.BytesPerSector = 512;
630 }
631
632 /* Check MBR type against EZ Drive type */
633 StartingOffset.QuadPart = 0;
634 HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data);
635 if (Data)
636 {
637 /* If MBR is of the EZ Drive type, we'll read after it */
638 StartingOffset.QuadPart = DiskGeometry.BytesPerSector;
639 ExFreePool(Data);
640 }
641
642 /* Allocate for reading enough data for checksum */
643 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO);
644 if (!PartitionBuffer)
645 {
646 ObDereferenceObject(FileObject);
647 Status = STATUS_INSUFFICIENT_RESOURCES;
648 goto Cleanup;
649 }
650
651 /* Read the first sector for computing checksum */
652 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
653 DeviceObject,
654 PartitionBuffer,
655 DiskGeometry.BytesPerSector,
656 &StartingOffset,
657 &Event,
658 &IoStatusBlock);
659 if (!Irp)
660 {
661 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
662 ObDereferenceObject(FileObject);
663 Status = STATUS_INSUFFICIENT_RESOURCES;
664 goto Cleanup;
665 }
666
667 /* Call the driver to perform reading */
668 KeInitializeEvent(&Event, NotificationEvent, FALSE);
669 Status = IoCallDriver(DeviceObject, Irp);
670 if (Status == STATUS_PENDING)
671 {
672 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
673 Status = IoStatusBlock.Status;
674 }
675
676 /* If reading succeeded, calculate checksum by adding data */
677 if (NT_SUCCESS(Status))
678 {
679 for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG); i++)
680 {
681 CheckSum += PartitionBuffer[i];
682 }
683 }
684
685 /* Release now unnecessary resources */
686 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
687 ObDereferenceObject(FileObject);
688
689 /* If we failed, release drive layout before going to next disk */
690 if (!NT_SUCCESS(Status))
691 {
692 ExFreePool(DriveLayout);
693 DriveLayout = NULL;
694 continue;
695 }
696
697 /* Browse each ARC disk */
698 for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
699 NextEntry != &ArcDiskInformation->DiskSignatureListHead;
700 NextEntry = NextEntry->Flink)
701 {
702 ArcDiskSignature = CONTAINING_RECORD(NextEntry,
703 ARC_DISK_SIGNATURE,
704 ListEntry);
705
706 /* If they match, i.e.
707 * - There's only one disk for both BIOS and detected/enabled
708 * - Signatures are matching
709 * - Checksums are matching
710 * - This is MBR
711 */
712 if (((SingleDisk && DiskCount == 1) ||
713 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) &&
714 (ArcDiskSignature->CheckSum + CheckSum == 0))) &&
715 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
716 {
717 /* Create device name */
718 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber);
719 RtlInitAnsiString(&DeviceStringA, Buffer);
720 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
721 if (!NT_SUCCESS(Status))
722 {
723 goto Cleanup;
724 }
725
726 /* Create ARC name */
727 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
728 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
729 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
730 if (!NT_SUCCESS(Status))
731 {
732 RtlFreeUnicodeString(&DeviceStringW);
733 goto Cleanup;
734 }
735
736 /* Link both */
737 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
738
739 /* And release resources */
740 RtlFreeUnicodeString(&ArcNameStringW);
741 RtlFreeUnicodeString(&DeviceStringW);
742
743 /* Now, browse for every partition */
744 for (i = 1; i <= DriveLayout->PartitionCount; i++)
745 {
746 /* Create device name */
747 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i);
748 RtlInitAnsiString(&DeviceStringA, Buffer);
749 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
750 if (!NT_SUCCESS(Status))
751 {
752 goto Cleanup;
753 }
754
755 /* Create partial ARC name */
756 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i);
757 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
758
759 /* Is that boot device? */
760 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
761 {
762 DPRINT("Found boot device\n");
763 *FoundBoot = TRUE;
764 }
765
766 /* Is that system partition? */
767 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
768 {
769 /* Create HAL path name */
770 RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName);
771 Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE);
772 if (!NT_SUCCESS(Status))
773 {
774 RtlFreeUnicodeString(&DeviceStringW);
775 goto Cleanup;
776 }
777
778 /* Then store those information to registry */
779 IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW);
780 RtlFreeUnicodeString(&HalPathStringW);
781 }
782
783 /* Create complete ARC name */
784 sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i);
785 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
786 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
787 if (!NT_SUCCESS(Status))
788 {
789 RtlFreeUnicodeString(&DeviceStringW);
790 goto Cleanup;
791 }
792
793 /* Link device name & ARC name */
794 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
795
796 /* Release strings */
797 RtlFreeUnicodeString(&ArcNameStringW);
798 RtlFreeUnicodeString(&DeviceStringW);
799 }
800 }
801 else
802 {
803 /* Debugging feedback: Warn in case there's a valid partition,
804 * a matching signature, BUT a non-matching checksum: this can
805 * be the sign of a duplicate signature, or even worse a virus
806 * played with the partition table. */
807 if (ArcDiskSignature->ValidPartitionTable &&
808 (ArcDiskSignature->Signature == Signature) &&
809 (ArcDiskSignature->CheckSum + CheckSum != 0))
810 {
811 DPRINT("Be careful, you have a duplicate disk signature, or a virus altered your MBR!\n");
812 }
813 }
814 }
815
816 /* Finally, release drive layout */
817 ExFreePool(DriveLayout);
818 DriveLayout = NULL;
819 }
820
821 Status = STATUS_SUCCESS;
822
823 Cleanup:
824 if (DriveLayout)
825 {
826 ExFreePool(DriveLayout);
827 }
828
829 if (SymbolicLinkList)
830 {
831 ExFreePool(SymbolicLinkList);
832 }
833
834 return Status;
835 }
836
837 CODE_SEG("INIT")
838 NTSTATUS
839 NTAPI
840 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
841 OUT PANSI_STRING NtBootPath)
842 {
843 OBJECT_ATTRIBUTES ObjectAttributes;
844 NTSTATUS Status;
845 CHAR Buffer[256], AnsiBuffer[256];
846 WCHAR ArcNameBuffer[64];
847 ANSI_STRING TargetString, ArcString, TempString;
848 UNICODE_STRING LinkName, TargetName, ArcName;
849 HANDLE LinkHandle;
850
851 /* Create the Unicode name for the current ARC boot device */
852 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
853 RtlInitAnsiString(&TargetString, Buffer);
854 Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
855 if (!NT_SUCCESS(Status)) return FALSE;
856
857 /* Initialize the attributes and open the link */
858 InitializeObjectAttributes(&ObjectAttributes,
859 &TargetName,
860 OBJ_CASE_INSENSITIVE,
861 NULL,
862 NULL);
863 Status = NtOpenSymbolicLinkObject(&LinkHandle,
864 SYMBOLIC_LINK_ALL_ACCESS,
865 &ObjectAttributes);
866 if (!NT_SUCCESS(Status))
867 {
868 /* We failed, free the string */
869 RtlFreeUnicodeString(&TargetName);
870 return FALSE;
871 }
872
873 /* Query the current \\SystemRoot */
874 ArcName.Buffer = ArcNameBuffer;
875 ArcName.Length = 0;
876 ArcName.MaximumLength = sizeof(ArcNameBuffer);
877 Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
878 if (!NT_SUCCESS(Status))
879 {
880 /* We failed, free the string */
881 RtlFreeUnicodeString(&TargetName);
882 return FALSE;
883 }
884
885 /* Convert it to Ansi */
886 ArcString.Buffer = AnsiBuffer;
887 ArcString.Length = 0;
888 ArcString.MaximumLength = sizeof(AnsiBuffer);
889 Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
890 AnsiBuffer[ArcString.Length] = ANSI_NULL;
891
892 /* Close the link handle and free the name */
893 ObCloseHandle(LinkHandle, KernelMode);
894 RtlFreeUnicodeString(&TargetName);
895
896 /* Setup the system root name again */
897 RtlInitAnsiString(&TempString, "\\SystemRoot");
898 Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
899 if (!NT_SUCCESS(Status)) return FALSE;
900
901 /* Open the symbolic link for it */
902 InitializeObjectAttributes(&ObjectAttributes,
903 &LinkName,
904 OBJ_CASE_INSENSITIVE,
905 NULL,
906 NULL);
907 Status = NtOpenSymbolicLinkObject(&LinkHandle,
908 SYMBOLIC_LINK_ALL_ACCESS,
909 &ObjectAttributes);
910 if (!NT_SUCCESS(Status)) return FALSE;
911
912 /* Destroy it */
913 NtMakeTemporaryObject(LinkHandle);
914 ObCloseHandle(LinkHandle, KernelMode);
915
916 /* Now create the new name for it */
917 sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
918
919 /* Copy it into the passed parameter and null-terminate it */
920 RtlCopyString(NtBootPath, &ArcString);
921 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
922
923 /* Setup the Unicode-name for the new symbolic link value */
924 RtlInitAnsiString(&TargetString, Buffer);
925 InitializeObjectAttributes(&ObjectAttributes,
926 &LinkName,
927 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
928 NULL,
929 NULL);
930 Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
931 if (!NT_SUCCESS(Status)) return FALSE;
932
933 /* Create it */
934 Status = NtCreateSymbolicLinkObject(&LinkHandle,
935 SYMBOLIC_LINK_ALL_ACCESS,
936 &ObjectAttributes,
937 &ArcName);
938
939 /* Free all the strings and close the handle and return success */
940 RtlFreeUnicodeString(&ArcName);
941 RtlFreeUnicodeString(&LinkName);
942 ObCloseHandle(LinkHandle, KernelMode);
943 return TRUE;
944 }
945
946 BOOLEAN
947 NTAPI
948 IopVerifyDiskSignature(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
949 IN PARC_DISK_SIGNATURE ArcDiskSignature,
950 OUT PULONG Signature)
951 {
952 /* First condition: having a valid partition table */
953 if (!ArcDiskSignature->ValidPartitionTable)
954 {
955 return FALSE;
956 }
957
958 /* If that partition table is the MBR */
959 if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)
960 {
961 /* Then check MBR signature */
962 if (DriveLayout->Mbr.Signature == ArcDiskSignature->Signature)
963 {
964 /* And return it */
965 if (Signature)
966 {
967 *Signature = DriveLayout->Mbr.Signature;
968 }
969
970 return TRUE;
971 }
972 }
973 /* If that partition table is the GPT */
974 else if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
975 {
976 /* Check we are using GPT and compare GUID */
977 if (ArcDiskSignature->IsGpt &&
978 (((PULONG)ArcDiskSignature->GptSignature)[0] == DriveLayout->Gpt.DiskId.Data1 &&
979 ((PUSHORT)ArcDiskSignature->GptSignature)[2] == DriveLayout->Gpt.DiskId.Data2 &&
980 ((PUSHORT)ArcDiskSignature->GptSignature)[3] == DriveLayout->Gpt.DiskId.Data3 &&
981 ((PULONGLONG)ArcDiskSignature->GptSignature)[1] == ((PULONGLONG)DriveLayout->Gpt.DiskId.Data4)[0]))
982 {
983 /* There's no signature to give, so we just zero output */
984 if (Signature)
985 {
986 *Signature = 0;
987 }
988 return TRUE;
989 }
990 }
991
992 /* If we fall here, it means that something went wrong, so return that */
993 return FALSE;
994 }
995
996 /* EOF */