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