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