static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject) /* * FUNCTION: Called on initialization to find our controllers and build device and controller objects for them * ARGUMENTS: * DriverObject: Our driver's DriverObject (so we can create devices against it) * RETURNS: * FALSE if we can't allocate a device, adapter, or interrupt object, or if we fail to find any controllers * TRUE otherwise (i.e. we have at least one fully-configured controller) * NOTES: * - Currently we only support ISA buses. * - BUG: Windows 2000 seems to clobber the response from the IoQueryDeviceDescription callback, so now we * just test a boolean value in the first object to see if it was completely populated. The same value * is tested for each controller before we build device objects for it. * TODO: * - Report resource usage to the HAL */ { INTERFACE_TYPE InterfaceType = Isa; CONFIGURATION_TYPE ControllerType = DiskController; CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral; KAFFINITY Affinity; DEVICE_DESCRIPTION DeviceDescription; UCHAR i; UCHAR j; PAGED_CODE(); /* Find our controllers on all ISA buses */ IoQueryDeviceDescription(&InterfaceType, 0, &ControllerType, 0, &PeripheralType, 0, ConfigCallback, 0); /* * w2k breaks the return val from ConfigCallback, so we have to hack around it, rather than just * looking for a return value from ConfigCallback. We expect at least one controller. */ if(!gControllerInfo[0].Populated) { WARN_(FLOPPY, "AddControllers: failed to get controller info from registry\n"); return FALSE; } /* Now that we have a controller, set it up with the system */ for(i = 0; i < gNumberOfControllers; i++) { /* 0: Report resource usage to the kernel, to make sure they aren't assigned to anyone else */ /* FIXME: Implement me. */ /* 1: Set up interrupt */ gControllerInfo[i].MappedVector = HalGetInterruptVector(gControllerInfo[i].InterfaceType, gControllerInfo[i].BusNumber, gControllerInfo[i].Level, gControllerInfo[i].Vector, &gControllerInfo[i].MappedLevel, &Affinity); /* Must set up the DPC before we connect the interrupt */ KeInitializeDpc(&gControllerInfo[i].Dpc, DpcForIsr, &gControllerInfo[i]); INFO_(FLOPPY, "Connecting interrupt %d to controller%d (object 0x%p)\n", gControllerInfo[i].MappedVector, i, &gControllerInfo[i]); /* NOTE: We cannot share our interrupt, even on level-triggered buses. See Isr() for details. */ if(IoConnectInterrupt(&gControllerInfo[i].InterruptObject, Isr, &gControllerInfo[i], 0, gControllerInfo[i].MappedVector, gControllerInfo[i].MappedLevel, gControllerInfo[i].MappedLevel, gControllerInfo[i].InterruptMode, FALSE, Affinity, 0) != STATUS_SUCCESS) { WARN_(FLOPPY, "AddControllers: unable to connect interrupt\n"); continue; } /* 2: Set up DMA */ memset(&DeviceDescription, 0, sizeof(DeviceDescription)); DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; DeviceDescription.DmaChannel = gControllerInfo[i].Dma; DeviceDescription.InterfaceType = gControllerInfo[i].InterfaceType; DeviceDescription.BusNumber = gControllerInfo[i].BusNumber; DeviceDescription.MaximumLength = 2*18*512; /* based on a 1.44MB floppy */ /* DMA 0,1,2,3 are 8-bit; 4,5,6,7 are 16-bit (4 is chain i think) */ DeviceDescription.DmaWidth = gControllerInfo[i].Dma > 3 ? Width16Bits: Width8Bits; gControllerInfo[i].AdapterObject = HalGetAdapter(&DeviceDescription, &gControllerInfo[i].MapRegisters); if(!gControllerInfo[i].AdapterObject) { WARN_(FLOPPY, "AddControllers: unable to allocate an adapter object\n"); IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); continue; } /* 2b: Initialize the new controller */ if(InitController(&gControllerInfo[i]) != STATUS_SUCCESS) { WARN_(FLOPPY, "AddControllers(): Unable to set up controller %d - initialization failed\n", i); IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); continue; } /* 2c: Set the controller's initlized flag so we know to release stuff in Unload */ gControllerInfo[i].Initialized = TRUE; /* 3: per-drive setup */ for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++) { WCHAR DeviceNameBuf[MAX_DEVICE_NAME]; UNICODE_STRING DeviceName; UNICODE_STRING LinkName; UNICODE_STRING ArcPath; UCHAR DriveNumber; INFO_(FLOPPY, "AddControllers(): Configuring drive %d on controller %d\n", i, j); /* * 3a: create a device object for the drive * Controllers and drives are 0-based, so the combos are: * 0: 0,0 * 1: 0,1 * 2: 0,2 * 3: 0,3 * 4: 1,0 * 5: 1,1 * ... * 14: 3,2 * 15: 3,3 */ DriveNumber = (UCHAR)(i*4 + j); /* loss of precision is OK; there are only 16 of 'em */ RtlZeroMemory(&DeviceNameBuf, MAX_DEVICE_NAME * sizeof(WCHAR)); swprintf(DeviceNameBuf, L"\\Device\\Floppy%d", DriveNumber); RtlInitUnicodeString(&DeviceName, DeviceNameBuf); if(IoCreateDevice(DriverObject, sizeof(PVOID), &DeviceName, FILE_DEVICE_DISK, FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, FALSE, &gControllerInfo[i].DriveInfo[j].DeviceObject) != STATUS_SUCCESS) { WARN_(FLOPPY, "AddControllers: unable to register a Device object\n"); IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); continue; /* continue on to next drive */ } INFO_(FLOPPY, "AddControllers: New device: %S (0x%p)\n", DeviceNameBuf, gControllerInfo[i].DriveInfo[j].DeviceObject); /* 3b.5: Create an ARC path in case we're booting from this drive */ swprintf(gControllerInfo[i].DriveInfo[j].ArcPathBuffer, L"\\ArcName\\multi(%d)disk(%d)fdisk(%d)", gControllerInfo[i].BusNumber, i, DriveNumber); RtlInitUnicodeString(&ArcPath, gControllerInfo[i].DriveInfo[j].ArcPathBuffer); IoAssignArcName(&ArcPath, &DeviceName); /* 3c: Set flags up */ gControllerInfo[i].DriveInfo[j].DeviceObject->Flags |= DO_DIRECT_IO; /* 3d: Create a symlink */ swprintf(gControllerInfo[i].DriveInfo[j].SymLinkBuffer, L"\\DosDevices\\%c:", DriveNumber + 'A'); RtlInitUnicodeString(&LinkName, gControllerInfo[i].DriveInfo[j].SymLinkBuffer); if(IoCreateSymbolicLink(&LinkName, &DeviceName) != STATUS_SUCCESS) { WARN_(FLOPPY, "AddControllers: Unable to create a symlink for drive %d\n", DriveNumber); IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); IoDeassignArcName(&ArcPath); continue; /* continue to next drive */ } /* 3e: Increase global floppy drives count */ IoGetConfigurationInformation()->FloppyCount++; /* 3f: Set up the DPC */ IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, (PIO_DPC_ROUTINE)DpcForIsr); /* 3g: Point the device extension at our DriveInfo struct */ gControllerInfo[i].DriveInfo[j].DeviceObject->DeviceExtension = &gControllerInfo[i].DriveInfo[j]; /* 3h: neat comic strip */ /* 3i: set the initial media type to unknown */ memset(&gControllerInfo[i].DriveInfo[j].DiskGeometry, 0, sizeof(DISK_GEOMETRY)); gControllerInfo[i].DriveInfo[j].DiskGeometry.MediaType = Unknown; /* 3j: Now that we're done, set the Initialized flag so we know to free this in Unload */ gControllerInfo[i].DriveInfo[j].Initialized = TRUE; /* 3k: Clear the DO_DEVICE_INITIALIZING flag */ gControllerInfo[i].DriveInfo[j].DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } } INFO_(FLOPPY, "AddControllers: --------------------------------------------> finished adding controllers\n"); return TRUE; }
NTSTATUS INIT_FUNCTION NTAPI IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock) { SIZE_T Length; NTSTATUS Status; CHAR Buffer[128]; BOOLEAN SingleDisk; BOOLEAN FoundBoot = FALSE; UNICODE_STRING SystemDevice, LoaderPathNameW, BootDeviceName; PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation; ANSI_STRING ArcSystemString, ArcString, LanmanRedirector, LoaderPathNameA; /* Check if we only have one disk on the machine */ SingleDisk = ArcDiskInfo->DiskSignatureListHead.Flink->Flink == (&ArcDiskInfo->DiskSignatureListHead); /* Create the global HAL partition name */ sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName); RtlInitAnsiString(&ArcString, Buffer); RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE); /* Create the global system partition name */ sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&ArcString, Buffer); RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE); /* Allocate memory for the string */ Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL); IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO); if (IoLoaderArcBootDeviceName) { /* Copy the name */ RtlCopyMemory(IoLoaderArcBootDeviceName, LoaderBlock->ArcBootDeviceName, Length); } /* Check if we only found a disk, but we're booting from CD-ROM */ if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom")) { /* Then disable single-disk mode, since there's a CD drive out there */ SingleDisk = FALSE; } /* Build the boot strings */ RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName); /* If we are doing remote booting */ if (IoRemoteBootClient) { /* Yes, we have found boot device */ FoundBoot = TRUE; /* Get NT device name */ RtlInitAnsiString(&LanmanRedirector, "\\Device\\LanmanRedirector"); Status = RtlAnsiStringToUnicodeString(&SystemDevice, &LanmanRedirector, TRUE); if (!NT_SUCCESS(Status)) { return Status; } /* Get ARC booting device name (in net(0) something) */ sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&ArcString, Buffer); Status = RtlAnsiStringToUnicodeString(&BootDeviceName, &ArcString, TRUE); if (NT_SUCCESS(Status)) { /* Map ARC to NT name */ IoAssignArcName(&BootDeviceName, &SystemDevice); RtlFreeUnicodeString(&BootDeviceName); /* Now, get loader path name */ RtlInitAnsiString(&LoaderPathNameA, LoaderBlock->NtHalPathName); Status = RtlAnsiStringToUnicodeString(&LoaderPathNameW, &LoaderPathNameA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&SystemDevice); return Status; } /* And set it has system partition */ IopStoreSystemPartitionInformation(&SystemDevice, &LoaderPathNameW); } RtlFreeUnicodeString(&SystemDevice); /* Don't quit here, even if everything went fine! * We need IopCreateArcNamesDisk to properly map * devices with symlinks. * It will return success if the mapping process went fine * even if it didn't find boot device. * It won't reset boot device finding status as well. */ } /* Loop every disk and try to find boot disk */ Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot); /* If it succeed but we didn't find boot device, try to browse Cds */ if (NT_SUCCESS(Status) && !FoundBoot) { Status = IopCreateArcNamesCd(LoaderBlock); } /* Return success */ return Status; }
NTSTATUS INIT_FUNCTION NTAPI IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN BOOLEAN SingleDisk, IN PBOOLEAN FoundBoot) { PIRP Irp; PVOID Data; KEVENT Event; NTSTATUS Status; PLIST_ENTRY NextEntry; PFILE_OBJECT FileObject; DISK_GEOMETRY DiskGeometry; PDEVICE_OBJECT DeviceObject; LARGE_INTEGER StartingOffset; PULONG PartitionBuffer = NULL; IO_STATUS_BLOCK IoStatusBlock; CHAR Buffer[128], ArcBuffer[128]; BOOLEAN NotEnabledPresent = FALSE; STORAGE_DEVICE_NUMBER DeviceNumber; PARC_DISK_SIGNATURE ArcDiskSignature; PWSTR SymbolicLinkList, lSymbolicLinkList; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL; UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW; ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0; PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation; ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA; /* Initialise device number */ DeviceNumber.DeviceNumber = ULONG_MAX; /* Get all the disks present in the system */ DiskCount = IoGetConfigurationInformation()->DiskCount; /* Get enabled disks and check if result matches */ Status = IopFetchConfigurationInformation(&SymbolicLinkList, GUID_DEVINTERFACE_DISK, DiskCount, &EnabledDisks); if (!NT_SUCCESS(Status)) { NotEnabledPresent = TRUE; } /* Save symbolic link list address in order to free it after */ lSymbolicLinkList = SymbolicLinkList; /* Build the boot strings */ RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName); /* If we have more enabled disks, take that into account */ if (EnabledDisks > DiskCount) { DiskCount = EnabledDisks; } /* If we'll have to browse for none enabled disks, fix higher count */ if (NotEnabledPresent && !EnabledDisks) { DiskCount += 20; } /* Finally, if in spite of all that work, we still don't have disks, leave */ if (!DiskCount) { goto Cleanup; } /* Start browsing disks */ for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++) { /* Check if we have an enabled disk */ if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL) { /* Create its device name using first symbolic link */ RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList); /* Then, update symbolic links list */ lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); /* Get its associated device object and file object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (NT_SUCCESS(Status)) { /* Now, we'll ask the device its device number */ Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, DeviceObject, NULL, 0, &DeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), FALSE, &Event, &IoStatusBlock); /* Missing resources is a shame... No need to go farther */ if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* If we didn't get the appriopriate data, just skip that disk */ if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } } /* End of enabled disks enumeration */ if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL) { /* No enabled disk worked, reset field */ if (DeviceNumber.DeviceNumber == ULONG_MAX) { DeviceNumber.DeviceNumber = 0; } /* Update disk number to enable the following not enabled disks */ if (DeviceNumber.DeviceNumber > DiskNumber) { DiskNumber = DeviceNumber.DeviceNumber; } /* Increase a bit more */ DiskCount = DiskNumber + 20; } } else { /* Create device name for the disk */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Get its device object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); RtlFreeUnicodeString(&DeviceStringW); /* This is a security measure, to ensure DiskNumber will be used */ DeviceNumber.DeviceNumber = ULONG_MAX; } /* Something failed somewhere earlier, just skip the disk */ if (!NT_SUCCESS(Status)) { continue; } /* Let's ask the disk for its geometry */ Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, DeviceObject, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), FALSE, &Event, &IoStatusBlock); /* Missing resources is a shame... No need to go farther */ if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* Failure, skip disk */ if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } /* Read the partition table */ Status = IoReadPartitionTableEx(DeviceObject, &DriveLayout); if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } /* Ensure we have at least 512 bytes per sector */ if (DiskGeometry.BytesPerSector < 512) { DiskGeometry.BytesPerSector = 512; } /* Check MBR type against EZ Drive type */ StartingOffset.QuadPart = 0; HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data); if (Data) { /* If MBR is of the EZ Drive type, we'll read after it */ StartingOffset.QuadPart = DiskGeometry.BytesPerSector; ExFreePool(Data); } /* Allocate for reading enough data for checksum */ PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO); if (!PartitionBuffer) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Read a sector for computing checksum */ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, PartitionBuffer, DiskGeometry.BytesPerSector, &StartingOffset, &Event, &IoStatusBlock); if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver to perform reading */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { ExFreePool(DriveLayout); ExFreePoolWithTag(PartitionBuffer, TAG_IO); ObDereferenceObject(FileObject); continue; } ObDereferenceObject(FileObject); /* Calculate checksum, that's an easy computation, just adds read data */ for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++) { CheckSum += PartitionBuffer[i]; } /* Browse each ARC disk */ for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; NextEntry != &ArcDiskInformation->DiskSignatureListHead; NextEntry = NextEntry->Flink) { ArcDiskSignature = CONTAINING_RECORD(NextEntry, ARC_DISK_SIGNATURE, ListEntry); /* If they matches, ie * - There's only one disk for both BIOS and detected/enabled * - Signatures are matching * - Checksums are matching * - This is MBR */ if (((SingleDisk && DiskCount == 1) || (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) && (ArcDiskSignature->CheckSum + CheckSum == 0))) && (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)) { /* Create device name */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Create ARC name */ sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Link both */ IoAssignArcName(&ArcNameStringW, &DeviceStringW); /* And release resources */ RtlFreeUnicodeString(&ArcNameStringW); RtlFreeUnicodeString(&DeviceStringW); /* Now, browse for every partition */ for (i = 1; i <= DriveLayout->PartitionCount; i++) { /* Create device name */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Create partial ARC name */ sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); /* Is that boot device? */ if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE)) { DPRINT("Found boot device\n"); *FoundBoot = TRUE; } /* Is that system partition? */ if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE)) { /* Create HAL path name */ RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName); Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Then store those information to registry */ IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW); RtlFreeUnicodeString(&HalPathStringW); } /* Create complete ARC name */ sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Link device name & ARC name */ IoAssignArcName(&ArcNameStringW, &DeviceStringW); /* Release strings */ RtlFreeUnicodeString(&ArcNameStringW); RtlFreeUnicodeString(&DeviceStringW); } } else { /* In case there's a valid partition, a matching signature, BUT a none matching checksum, or there's a duplicate signature, or even worse a virus played with partition table */ if (ArcDiskSignature->Signature == Signature && (ArcDiskSignature->CheckSum + CheckSum != 0) && ArcDiskSignature->ValidPartitionTable) { DPRINT("Be careful, or you have a duplicate disk signature, or a virus altered your MBR!\n"); } } } /* Release memory before jumping to next item */ ExFreePool(DriveLayout); DriveLayout = NULL; ExFreePoolWithTag(PartitionBuffer, TAG_IO); PartitionBuffer = NULL; } Status = STATUS_SUCCESS; Cleanup: if (SymbolicLinkList) { ExFreePool(SymbolicLinkList); } if (DriveLayout) { ExFreePool(DriveLayout); } if (PartitionBuffer) { ExFreePoolWithTag(PartitionBuffer, TAG_IO); } return Status; }
NTSTATUS INIT_FUNCTION NTAPI IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock) { PIRP Irp; KEVENT Event; NTSTATUS Status; PLIST_ENTRY NextEntry; PFILE_OBJECT FileObject; PDEVICE_OBJECT DeviceObject; LARGE_INTEGER StartingOffset; IO_STATUS_BLOCK IoStatusBlock; PULONG PartitionBuffer = NULL; CHAR Buffer[128], ArcBuffer[128]; BOOLEAN NotEnabledPresent = FALSE; STORAGE_DEVICE_NUMBER DeviceNumber; ANSI_STRING DeviceStringA, ArcNameStringA; PWSTR SymbolicLinkList, lSymbolicLinkList; PARC_DISK_SIGNATURE ArcDiskSignature = NULL; UNICODE_STRING DeviceStringW, ArcNameStringW; ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0; PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation; /* Get all the Cds present in the system */ CdRomCount = IoGetConfigurationInformation()->CdRomCount; /* Get enabled Cds and check if result matches * For the record, enabled Cds (or even disk) are Cds/disks * that have been successfully handled by MountMgr driver * and that already own their device name. This is the "new" way * to handle them, that came with NT5. * Currently, Windows 2003 provides an arc names creation based * on both enabled drives and not enabled drives (lack from * the driver). * Given the current ReactOS state, that's good for us. * To sum up, this is NOT a hack or whatsoever. */ Status = IopFetchConfigurationInformation(&SymbolicLinkList, GUID_DEVINTERFACE_CDROM, CdRomCount, &EnabledDisks); if (!NT_SUCCESS(Status)) { NotEnabledPresent = TRUE; } /* Save symbolic link list address in order to free it after */ lSymbolicLinkList = SymbolicLinkList; /* For the moment, we won't fail */ Status = STATUS_SUCCESS; /* Browse all the ARC devices trying to find the one matching boot device */ for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; NextEntry != &ArcDiskInformation->DiskSignatureListHead; NextEntry = NextEntry->Flink) { ArcDiskSignature = CONTAINING_RECORD(NextEntry, ARC_DISK_SIGNATURE, ListEntry); if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0) { break; } ArcDiskSignature = NULL; } /* Not found... Not booting from a Cd */ if (!ArcDiskSignature) { DPRINT("Failed finding a cd that could match current boot device\n"); goto Cleanup; } /* Allocate needed space for reading Cd */ PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO); if (!PartitionBuffer) { DPRINT("Failed allocating resources!\n"); /* Here, we fail, BUT we return success, some Microsoft joke */ goto Cleanup; } /* If we have more enabled Cds, take that into account */ if (EnabledDisks > CdRomCount) { CdRomCount = EnabledDisks; } /* If we'll have to browse for none enabled Cds, fix higher count */ if (NotEnabledPresent && !EnabledDisks) { CdRomCount += 5; } /* Finally, if in spite of all that work, we still don't have Cds, leave */ if (!CdRomCount) { goto Cleanup; } /* Start browsing Cds */ for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++) { /* Check if we have an enabled disk */ if (SymbolicLinkList && *SymbolicLinkList != UNICODE_NULL) { /* Create its device name using first symbolic link */ RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList); /* Then, update symbolic links list */ lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); /* Get its associated device object and file object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); /* Failure? Good bye! */ if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Now, we'll ask the device its device number */ Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, DeviceObject, NULL, 0, &DeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), FALSE, &Event, &IoStatusBlock); /* Failure? Good bye! */ if (!Irp) { /* Dereference file object before leaving */ ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); goto Cleanup; } /* Finally, build proper device name */ sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); goto Cleanup; } } else { /* Create device name for the cd */ sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Get its device object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } } /* Initiate data for reading cd and compute checksum */ StartingOffset.QuadPart = 0x8000; CheckSum = 0; Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, PartitionBuffer, 2048, &StartingOffset, &Event, &IoStatusBlock); if (Irp) { /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* Reading succeed, compute checksum by adding data, 2048 bytes checksum */ if (NT_SUCCESS(Status)) { for (i = 0; i < 2048 / sizeof(ULONG); i++) { CheckSum += PartitionBuffer[i]; } } } /* Dereference file object */ ObDereferenceObject(FileObject); /* If checksums are matching, we have the proper cd */ if (CheckSum + ArcDiskSignature->CheckSum == 0) { /* Create ARC name */ sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); if (NT_SUCCESS(Status)) { /* Create symbolic link */ IoAssignArcName(&ArcNameStringW, &DeviceStringW); RtlFreeUnicodeString(&ArcNameStringW); DPRINT("Boot device found\n"); } /* And quit, whatever happens */ RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Free string before trying another disk */ RtlFreeUnicodeString(&DeviceStringW); } Cleanup: if (PartitionBuffer) { ExFreePoolWithTag(PartitionBuffer, TAG_IO); } if (SymbolicLinkList) { ExFreePool(SymbolicLinkList); } return Status; }