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
IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)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
IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock)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
IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,IN BOOLEAN SingleDisk,OUT PBOOLEAN FoundBoot)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 appropriate 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 /*
707 * If this is the only MBR disk in the ARC list and detected
708 * in the device tree, just go ahead and create the ArcName link.
709 * Otherwise, check whether the signatures and checksums match
710 * before creating the ArcName link.
711 */
712 if ((SingleDisk && (DiskCount == 1) &&
713 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)) ||
714 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) &&
715 (ArcDiskSignature->CheckSum + CheckSum == 0)))
716 {
717 /* Create device name */
718 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0",
719 (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber);
720 RtlInitAnsiString(&DeviceStringA, Buffer);
721 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
722 if (!NT_SUCCESS(Status))
723 {
724 goto Cleanup;
725 }
726
727 /* Create ARC name */
728 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
729 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
730 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
731 if (!NT_SUCCESS(Status))
732 {
733 RtlFreeUnicodeString(&DeviceStringW);
734 goto Cleanup;
735 }
736
737 /* Link both */
738 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
739
740 /* And release strings */
741 RtlFreeUnicodeString(&ArcNameStringW);
742 RtlFreeUnicodeString(&DeviceStringW);
743
744 /* Now, browse each partition */
745 for (i = 1; i <= DriveLayout->PartitionCount; i++)
746 {
747 /* Create device name */
748 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu",
749 (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i);
750 RtlInitAnsiString(&DeviceStringA, Buffer);
751 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
752 if (!NT_SUCCESS(Status))
753 {
754 goto Cleanup;
755 }
756
757 /* Create partial ARC name */
758 sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i);
759 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
760
761 /* Is that boot device? */
762 if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
763 {
764 DPRINT("Found boot device\n");
765 *FoundBoot = TRUE;
766 }
767
768 /* Is that system partition? */
769 if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
770 {
771 /* Create HAL path name */
772 RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName);
773 Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE);
774 if (!NT_SUCCESS(Status))
775 {
776 RtlFreeUnicodeString(&DeviceStringW);
777 goto Cleanup;
778 }
779
780 /* Then store those information to registry */
781 IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW);
782 RtlFreeUnicodeString(&HalPathStringW);
783 }
784
785 /* Create complete ARC name */
786 sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i);
787 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
788 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
789 if (!NT_SUCCESS(Status))
790 {
791 RtlFreeUnicodeString(&DeviceStringW);
792 goto Cleanup;
793 }
794
795 /* Link device name & ARC name */
796 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
797
798 /* Release strings */
799 RtlFreeUnicodeString(&ArcNameStringW);
800 RtlFreeUnicodeString(&DeviceStringW);
801 }
802 }
803 else
804 {
805 /* Debugging feedback: Warn in case there's a valid partition,
806 * a matching signature, BUT a non-matching checksum: this can
807 * be the sign of a duplicate signature, or even worse a virus
808 * played with the partition table. */
809 if (ArcDiskSignature->ValidPartitionTable &&
810 (ArcDiskSignature->Signature == Signature) &&
811 (ArcDiskSignature->CheckSum + CheckSum != 0))
812 {
813 DPRINT("Be careful, you have a duplicate disk signature, or a virus altered your MBR!\n");
814 }
815 }
816 }
817
818 /* Finally, release drive layout */
819 ExFreePool(DriveLayout);
820 DriveLayout = NULL;
821 }
822
823 Status = STATUS_SUCCESS;
824
825 Cleanup:
826 if (DriveLayout)
827 {
828 ExFreePool(DriveLayout);
829 }
830
831 if (SymbolicLinkList)
832 {
833 ExFreePool(SymbolicLinkList);
834 }
835
836 return Status;
837 }
838
839 CODE_SEG("INIT")
840 NTSTATUS
841 NTAPI
IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,OUT PANSI_STRING NtBootPath)842 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
843 OUT PANSI_STRING NtBootPath)
844 {
845 OBJECT_ATTRIBUTES ObjectAttributes;
846 NTSTATUS Status;
847 CHAR Buffer[256], AnsiBuffer[256];
848 WCHAR ArcNameBuffer[64];
849 ANSI_STRING TargetString, ArcString, TempString;
850 UNICODE_STRING LinkName, TargetName, ArcName;
851 HANDLE LinkHandle;
852
853 /* Create the Unicode name for the current ARC boot device */
854 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
855 RtlInitAnsiString(&TargetString, Buffer);
856 Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
857 if (!NT_SUCCESS(Status)) return FALSE;
858
859 /* Initialize the attributes and open the link */
860 InitializeObjectAttributes(&ObjectAttributes,
861 &TargetName,
862 OBJ_CASE_INSENSITIVE,
863 NULL,
864 NULL);
865 Status = NtOpenSymbolicLinkObject(&LinkHandle,
866 SYMBOLIC_LINK_ALL_ACCESS,
867 &ObjectAttributes);
868 if (!NT_SUCCESS(Status))
869 {
870 /* We failed, free the string */
871 RtlFreeUnicodeString(&TargetName);
872 return FALSE;
873 }
874
875 /* Query the current \\SystemRoot */
876 ArcName.Buffer = ArcNameBuffer;
877 ArcName.Length = 0;
878 ArcName.MaximumLength = sizeof(ArcNameBuffer);
879 Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
880 if (!NT_SUCCESS(Status))
881 {
882 /* We failed, free the string */
883 RtlFreeUnicodeString(&TargetName);
884 return FALSE;
885 }
886
887 /* Convert it to Ansi */
888 ArcString.Buffer = AnsiBuffer;
889 ArcString.Length = 0;
890 ArcString.MaximumLength = sizeof(AnsiBuffer);
891 Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
892 AnsiBuffer[ArcString.Length] = ANSI_NULL;
893
894 /* Close the link handle and free the name */
895 ObCloseHandle(LinkHandle, KernelMode);
896 RtlFreeUnicodeString(&TargetName);
897
898 /* Setup the system root name again */
899 RtlInitAnsiString(&TempString, "\\SystemRoot");
900 Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
901 if (!NT_SUCCESS(Status)) return FALSE;
902
903 /* Open the symbolic link for it */
904 InitializeObjectAttributes(&ObjectAttributes,
905 &LinkName,
906 OBJ_CASE_INSENSITIVE,
907 NULL,
908 NULL);
909 Status = NtOpenSymbolicLinkObject(&LinkHandle,
910 SYMBOLIC_LINK_ALL_ACCESS,
911 &ObjectAttributes);
912 if (!NT_SUCCESS(Status)) return FALSE;
913
914 /* Destroy it */
915 NtMakeTemporaryObject(LinkHandle);
916 ObCloseHandle(LinkHandle, KernelMode);
917
918 /* Now create the new name for it */
919 sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
920
921 /* Copy it into the passed parameter and null-terminate it */
922 RtlCopyString(NtBootPath, &ArcString);
923 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
924
925 /* Setup the Unicode-name for the new symbolic link value */
926 RtlInitAnsiString(&TargetString, Buffer);
927 InitializeObjectAttributes(&ObjectAttributes,
928 &LinkName,
929 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
930 NULL,
931 NULL);
932 Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
933 if (!NT_SUCCESS(Status)) return FALSE;
934
935 /* Create it */
936 Status = NtCreateSymbolicLinkObject(&LinkHandle,
937 SYMBOLIC_LINK_ALL_ACCESS,
938 &ObjectAttributes,
939 &ArcName);
940
941 /* Free all the strings and close the handle and return success */
942 RtlFreeUnicodeString(&ArcName);
943 RtlFreeUnicodeString(&LinkName);
944 ObCloseHandle(LinkHandle, KernelMode);
945 return TRUE;
946 }
947
948 BOOLEAN
IopVerifyDiskSignature(_In_ PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,_In_ PARC_DISK_SIGNATURE ArcDiskSignature,_Out_ PULONG Signature)949 IopVerifyDiskSignature(
950 _In_ PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
951 _In_ PARC_DISK_SIGNATURE ArcDiskSignature,
952 _Out_ PULONG Signature)
953 {
954 /* Fail if the partition table is invalid */
955 if (!ArcDiskSignature->ValidPartitionTable)
956 return FALSE;
957
958 /* If the partition style is MBR */
959 if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)
960 {
961 /* Check the MBR signature */
962 if (DriveLayout->Mbr.Signature == ArcDiskSignature->Signature)
963 {
964 /* And return it */
965 if (Signature)
966 *Signature = DriveLayout->Mbr.Signature;
967 return TRUE;
968 }
969 }
970 /* If the partition style is GPT */
971 else if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
972 {
973 /* Verify whether the signature is GPT and compare the GUID */
974 if (ArcDiskSignature->IsGpt &&
975 IsEqualGUID((PGUID)&ArcDiskSignature->GptSignature, &DriveLayout->Gpt.DiskId))
976 {
977 /* There is no signature to return, just zero it */
978 if (Signature)
979 *Signature = 0;
980 return TRUE;
981 }
982 }
983
984 /* If we get there, something went wrong, so fail */
985 return FALSE;
986 }
987
988 /* EOF */
989