/*++ Copyright (c) 2001 Microsoft Corporation Module Name: uninstall.c Abstract: General uninstall-related functions. Author: Aghajanyan Souren 27-Mar-2001 Revision History: --*/ #include "pch.h" #include "uninstall.h" #define PARTITIONS_DEFAULT_NUMBER 128 BOOL GetDiskInfo( IN UINT Drive, IN OUT DISKINFO * pInfo ) { HANDLE hDisk = NULL; DWORD dwBytesReturned; DWORD dwLastError; UINT uiBufferSize; BOOL bResult; TCHAR diskPath[MAX_PATH]; DRIVE_LAYOUT_INFORMATION_EX * pinfoLayoutEx = NULL; if(!pInfo){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } __try{ StringCbPrintf(diskPath, sizeof(diskPath), TEXT("\\\\.\\PHYSICALDRIVE%d"), Drive); hDisk = CreateFile(diskPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hDisk){ dwLastError = GetLastError(); __leave; } StringCbAppendWack(diskPath, sizeof(diskPath)); if(DRIVE_FIXED != GetDriveType(diskPath)){ dwLastError = ERROR_ACCESS_DENIED; __leave; } dwBytesReturned = 0; bResult = DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &pInfo->DiskGeometry, sizeof(pInfo->DiskGeometry), &dwBytesReturned, NULL); if(!bResult){ dwLastError = GetLastError(); LOG((LOG_WARNING, "GetDiskInfo:DeviceIoControl(%s, IOCTL_DISK_GET_DRIVE_GEOMETRY) failed.", diskPath)); __leave; } uiBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX); do{ uiBufferSize += PARTITIONS_DEFAULT_NUMBER * sizeof(PARTITION_INFORMATION_EX); if(pinfoLayoutEx){ FreeMem(pinfoLayoutEx); } pinfoLayoutEx = (DRIVE_LAYOUT_INFORMATION_EX *)MemAllocZeroed(uiBufferSize); if(!pinfoLayoutEx){ dwLastError = ERROR_NOT_ENOUGH_MEMORY; __leave; } dwBytesReturned = 0; bResult = DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, pinfoLayoutEx, uiBufferSize, &dwBytesReturned, NULL); }while(!bResult && ERROR_INSUFFICIENT_BUFFER == GetLastError()); if(!bResult){ dwLastError = GetLastError(); LOG((LOG_WARNING, "GetDiskInfo:DeviceIoControl(%s, IOCTL_DISK_GET_DRIVE_LAYOUT_EX) failed.", diskPath)); __leave; } pInfo->DiskLayout = pinfoLayoutEx; dwLastError = ERROR_SUCCESS; } __except(EXCEPTION_EXECUTE_HANDLER){ if(pinfoLayoutEx){ FreeMem(pinfoLayoutEx); } } if(hDisk){ CloseHandle(hDisk); } SetLastError(dwLastError); return ERROR_SUCCESS == dwLastError; } BOOL GetPhysycalDiskNumber( OUT UINT * pNumberOfPhysicalDisks ) { TCHAR diskPath[MAX_PATH]; HANDLE hDisk; UINT i; if(!pNumberOfPhysicalDisks){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } *pNumberOfPhysicalDisks = 0; for(i = 0; ; i++){ StringCbPrintf(diskPath, sizeof(diskPath), TEXT("\\\\.\\PHYSICALDRIVE%d"), i); hDisk = CreateFile(diskPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hDisk){ MYASSERT(GetLastError() == ERROR_FILE_NOT_FOUND); break; } CloseHandle(hDisk); StringCbAppendWack(diskPath, sizeof(diskPath)); if(DRIVE_FIXED != GetDriveType(diskPath)){ continue; } (*pNumberOfPhysicalDisks)++; } SetLastError(ERROR_SUCCESS); return TRUE; } BOOL GetDisksInfo( OUT DISKINFO ** pInfo, OUT UINT * pNumberOfItem ) { UINT i; UINT diskNumber; if(!pInfo || !pNumberOfItem){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } if(!GetPhysycalDiskNumber(pNumberOfItem)){ DEBUGMSG((DBG_ERROR, "GetDisksInfo:GetPhysycalDiskNumber failed")); return FALSE; } *pInfo = (DISKINFO *)MemAllocZeroed(*pNumberOfItem * sizeof(DISKINFO)); if(!*pInfo){ SetLastError(ERROR_NOT_ENOUGH_MEMORY); LOG((LOG_WARNING, "GetDisksInfo:MemAlloc failed to allocate memory for %d disks", *pNumberOfItem)); return FALSE; } diskNumber = 0; for(i = 0; i < *pNumberOfItem; i++){ while(!GetDiskInfo(diskNumber++, (*pInfo) + i)){ if(ERROR_ACCESS_DENIED == GetLastError()){ continue; } if(ERROR_FILE_NOT_FOUND == GetLastError()){ break; } LOG((LOG_WARNING, "GetDisksInfo:GetDiskInfo(phisycaldisk%d) failed with total %d", diskNumber, *pNumberOfItem)); FreeDisksInfo(*pInfo, *pNumberOfItem); return FALSE; } } SetLastError(ERROR_SUCCESS); return TRUE; } VOID FreeDisksInfo( IN DISKINFO * pInfo, IN UINT NumberOfItem ) { UINT i; if(!pInfo || !NumberOfItem){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return; } __try{ for(i = 0; i < NumberOfItem; i++){ if(pInfo[i].DiskLayout){ FreeMem(pInfo[i].DiskLayout); } } FreeMem(pInfo); } __except(EXCEPTION_EXECUTE_HANDLER){ DEBUGMSG((DBG_ERROR, "FreeDisksInfo throwed exception")); } } //BUGBUG -- ISSUE -- This function assumes that the members of pInfo are allocated //with the appropriate minimum sizes!!! BOOL GetDriveInfo( IN WCHAR Drive, IN OUT DRIVEINFO * pInfo ) { WCHAR driveDosPath[] = L"?:\\"; WCHAR driveDosDeviceVolumeMountPoint[MAX_PATH]; BOOL result; if(!pInfo || !pInfo->FileSystemName || !pInfo->VolumeNTPath){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } pInfo->Drive = Drive; driveDosPath[0] = Drive; if(!GetVolumeNameForVolumeMountPointW(driveDosPath, driveDosDeviceVolumeMountPoint, ARRAYSIZE(driveDosDeviceVolumeMountPoint))){ DEBUGMSGW((DBG_WARNING, "GetDiskInfo:GetVolumeNameForVolumeMountPoint(%s) failed", driveDosPath)); SetLastError(ERROR_ACCESS_DENIED); return FALSE; } //BUGBUG assumes VolumeNTPath has size MAX_PATH. In a search of the codebase in ntsetup, I found //this to be the case wcscpy((LPWSTR)pInfo->VolumeNTPath, driveDosDeviceVolumeMountPoint); result = GetVolumeInformationW( driveDosPath, NULL, 0, NULL, NULL, &pInfo->FileSystemFlags, (LPWSTR)pInfo->FileSystemName, MAX_PATH ); if(!result && (GetLastError() == ERROR_UNRECOGNIZED_VOLUME)){ //BUGBUG assumes FileSystemName has size MAX_PATH. In a search of the codebase in ntsetup, I found //this to be the case wcscpy((LPWSTR)pInfo->FileSystemName, L"UNRECOGNIZED_VOLUME"); result = TRUE; DEBUGMSGW((DBG_WARNING, "GetDiskInfo:GetVolumeInformation(%s):GetLastError() == ERROR_UNRECOGNIZED_VOLUME", driveDosPath)); } DEBUGMSGW_IF((!result, DBG_ERROR, "GetDiskInfo:GetVolumeInformation(%s):GetLastError() == %d", driveDosPath, GetLastError())); return result; } BOOL GetIntegrityInfoW( IN PCWSTR FileName, IN PCWSTR DirPath, OUT FILEINTEGRITYINFO * IntegrityInfoPtr ) { WCHAR pathFile[MAX_PATH]; if(!FileName || !DirPath || !IntegrityInfoPtr){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } #pragma prefast(suppress:209, "Use of sizeof(pathFile) is correct") StringCbCopyW(pathFile, sizeof(pathFile), DirPath); #pragma prefast(suppress:209, "Use of sizeof(pathFile) is correct") StringCbCatW(StringCbAppendWackW(pathFile, sizeof(pathFile)), sizeof(pathFile),FileName); //BUGBUG assumes FileName is of size MAX_PATH. StringCopyW((LPWSTR)IntegrityInfoPtr->FileName, FileName); if(!GetFileSizeFromFilePathW(pathFile, &IntegrityInfoPtr->FileSize)){ return FALSE; } SetLastError(ERROR_SUCCESS); return TRUE; } BOOL GetDrivesInfo( IN OUT DRIVEINFO * pInfo, IN OUT UINT * pDiskInfoRealCount, IN UINT DiskInfoMaxCount ) { UINT LogicalDrives; WCHAR DriveName[] = L"?:\\"; UINT i; if(!pDiskInfoRealCount){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } if(!(LogicalDrives = GetLogicalDrives())) { return FALSE; } *pDiskInfoRealCount = 0; for(i = 0; LogicalDrives && ((*pDiskInfoRealCount) < DiskInfoMaxCount); LogicalDrives >>= 1, i++){ if(LogicalDrives&1) { DriveName[0] = 'A' + (char)i; if(DRIVE_FIXED != GetDriveTypeW(DriveName)) { continue; } if(pInfo){ if(!GetDriveInfo(DriveName[0], pInfo++)){ MYASSERT(FALSE); return FALSE; } } (*pDiskInfoRealCount)++; } } SetLastError(ERROR_SUCCESS); return TRUE; } BOOL GetUndoDrivesInfo( OUT DRIVEINFO * pInfo, OUT UINT * pNumberOfDrive, IN WCHAR BootDrive, IN WCHAR SystemDrive, IN WCHAR UndoDrive ) { if(!pInfo || !pNumberOfDrive){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return FALSE; } *pNumberOfDrive = 0; if(!GetDriveInfo(BootDrive, pInfo++)){ MYASSERT(FALSE); return FALSE; } (*pNumberOfDrive)++; if(SystemDrive != BootDrive){ if(!GetDriveInfo(SystemDrive, pInfo++)){ MYASSERT(FALSE); return FALSE; } (*pNumberOfDrive)++; } if(UndoDrive != BootDrive && UndoDrive != SystemDrive){ if(!GetDriveInfo(UndoDrive, pInfo++)){ MYASSERT(FALSE); return FALSE; } (*pNumberOfDrive)++; } SetLastError(ERROR_SUCCESS); return TRUE; } DISKINFO_COMPARATION_STATUS CompareDriveInfo( IN DRIVEINFO * FirstInfo, IN DRIVEINFO * SecondInfo ) { if(!FirstInfo || !SecondInfo){ MYASSERT(FALSE); return DiskInfoCmp_WrongParameters; } if(towlower(FirstInfo->Drive) != towlower(SecondInfo->Drive)){ return DiskInfoCmp_DifferentLetter; } MYASSERT(FirstInfo->FileSystemName && SecondInfo->FileSystemName); if(wcscmp(FirstInfo->FileSystemName, SecondInfo->FileSystemName)){ return DiskInfoCmp_FileSystemHasChanged; } if(FirstInfo->FileSystemFlags != SecondInfo->FileSystemFlags){ return DiskInfoCmp_FileSystemHasChanged; } MYASSERT(FirstInfo->VolumeNTPath && SecondInfo->VolumeNTPath); if(wcscmp(FirstInfo->VolumeNTPath, SecondInfo->VolumeNTPath)){ return DiskInfoCmp_DriveMountPointHasChanged; } return DiskInfoCmp_Equal; } BOOL CompareDrivesInfo( IN DRIVEINFO * FirstInfo, IN DRIVEINFO * SecondInfo, IN UINT DriveInfoCount, OUT PDISKINFO_COMPARATION_STATUS OutDiskCmpStatus, OPTIONAL OUT UINT * OutIfFailedDiskInfoIndex OPTIONAL ) { UINT i; DISKINFO_COMPARATION_STATUS cmpStatus; if(!FirstInfo || !SecondInfo || !DriveInfoCount){ MYASSERT(FALSE); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } for(i = 0; i < DriveInfoCount; i++){ cmpStatus = CompareDriveInfo(FirstInfo++, SecondInfo++); if(DiskInfoCmp_Equal != cmpStatus){ if(OutDiskCmpStatus){ *OutDiskCmpStatus = cmpStatus; } if(OutIfFailedDiskInfoIndex){ *OutIfFailedDiskInfoIndex = i; } SetLastError(ERROR_ACCESS_DENIED); return FALSE; } } SetLastError(ERROR_SUCCESS); return TRUE; } DISKINFO_COMPARATION_STATUS CompareDiskInfo( IN DISKINFO * FirstInfo, IN DISKINFO * SecondInfo ) { DWORD i, iLen; PARTITION_INFORMATION_EX * pPartition1; PARTITION_INFORMATION_EX * pPartition2; if(!FirstInfo || !SecondInfo || !FirstInfo->DiskLayout || !SecondInfo->DiskLayout){ MYASSERT(FALSE); return DiskInfoCmp_WrongParameters; } // //DISK_GEOMETRY // if(memcmp(&FirstInfo->DiskGeometry, &SecondInfo->DiskGeometry, sizeof(FirstInfo->DiskGeometry))){ return DiskInfoCmp_GeometryHasChanged; } // //DRIVE_LAYOUT_INFORMATION_EX // if(FirstInfo->DiskLayout->PartitionStyle != SecondInfo->DiskLayout->PartitionStyle){ return DiskInfoCmp_PartitionStyleHasChanged; } if(FirstInfo->DiskLayout->PartitionCount != SecondInfo->DiskLayout->PartitionCount){ return DiskInfoCmp_PartitionCountHasChanged; } // //PARTITION_INFORMATION // for(i = 0, iLen = FirstInfo->DiskLayout->PartitionCount; i < iLen; i++){ pPartition1 = &FirstInfo->DiskLayout->PartitionEntry[i]; pPartition2 = &SecondInfo->DiskLayout->PartitionEntry[i]; if(pPartition1->PartitionStyle != pPartition2->PartitionStyle){ return DiskInfoCmp_PartitionStyleHasChanged; } if(pPartition1->StartingOffset.QuadPart != pPartition2->StartingOffset.QuadPart){ return DiskInfoCmp_PartitionPlaceHasChanged; } if(pPartition1->PartitionLength.QuadPart != pPartition2->PartitionLength.QuadPart){ return DiskInfoCmp_PartitionLengthHasChanged; } if(pPartition1->PartitionNumber != pPartition2->PartitionNumber){ return DiskInfoCmp_PartitionNumberHasChanged; } if(pPartition1->RewritePartition != pPartition2->RewritePartition){ return DiskInfoCmp_RewritePartitionHasChanged; } if(pPartition1->PartitionStyle == PARTITION_STYLE_MBR){ if(pPartition1->Mbr.PartitionType != pPartition2->Mbr.PartitionType){ return DiskInfoCmp_PartitionTypeHasChanged; } if(pPartition1->Mbr.BootIndicator != pPartition2->Mbr.BootIndicator){ return DiskInfoCmp_PartitionAttributesHasChanged; } if(pPartition1->Mbr.RecognizedPartition != pPartition2->Mbr.RecognizedPartition){ return DiskInfoCmp_PartitionAttributesHasChanged; } if(pPartition1->Mbr.HiddenSectors != pPartition2->Mbr.HiddenSectors){ return DiskInfoCmp_PartitionAttributesHasChanged; } } else if(pPartition1->PartitionStyle == PARTITION_STYLE_GPT){ if(memcmp(&pPartition1->Gpt, &pPartition2->Gpt, sizeof(pPartition1->Mbr))){ return DiskInfoCmp_PartitionAttributesHasChanged; } } } return DiskInfoCmp_Equal; } BOOL CompareDisksInfo( IN DISKINFO * FirstInfo, IN DISKINFO * SecondInfo, IN UINT DiskInfoCount, OUT PDISKINFO_COMPARATION_STATUS OutDiskCmpStatus, OPTIONAL OUT UINT * OutIfFailedDiskInfoIndex OPTIONAL ) { UINT i; DISKINFO_COMPARATION_STATUS cmpStatus; if(!FirstInfo || !SecondInfo || !DiskInfoCount){ MYASSERT(FALSE); return FALSE; } for(i = 0; i < DiskInfoCount; i++){ cmpStatus = CompareDiskInfo(FirstInfo++, SecondInfo++); if(DiskInfoCmp_Equal != cmpStatus){ if(OutDiskCmpStatus){ *OutDiskCmpStatus = cmpStatus; } if(OutIfFailedDiskInfoIndex){ *OutIfFailedDiskInfoIndex = i; } return FALSE; } } return TRUE; } BOOL IsFloppyDiskInDrive( VOID ) { WCHAR Drive[] = L"?:\\"; WCHAR DriveNT[] = L"\\\\.\\?:"; UINT i; HANDLE hDiskDrive; BOOL bDiskInDrive = FALSE; BOOL bResult; DISK_GEOMETRY diskGeometry; DWORD bytesReturned; DWORD Drives; for(i = 0, Drives = 0x7/*GetLogicalDrives()*/; Drives; Drives >>= 1, i++){ if(!(Drives&1)){ continue; } Drive[0] = 'A' + i; if(DRIVE_REMOVABLE != GetDriveTypeW(Drive)){ continue; } DriveNT[4] = Drive[0]; while(1){ hDiskDrive = CreateFileW(DriveNT, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hDiskDrive){ break; } bResult = DeviceIoControl(hDiskDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(diskGeometry), &bytesReturned, NULL); CloseHandle(hDiskDrive); if(bResult){ bDiskInDrive = diskGeometry.MediaType != Unknown && diskGeometry.MediaType != RemovableMedia && diskGeometry.MediaType != FixedMedia; break; } if(ERROR_MEDIA_CHANGED != GetLastError()){ break; } } if(bDiskInDrive){ break; } } return bDiskInDrive; } BOOL GetHardDiskNumberW( IN WCHAR DriveLetter, OUT UINT * HarddiskNumberOut ) { WCHAR driveName[] = L"\\\\.\\?:"; HANDLE hDisk; STORAGE_DEVICE_NUMBER deviceNumber; BOOL bResult; DWORD dwBytesReturned; driveName[4] = DriveLetter; hDisk = CreateFileW(driveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hDisk){ return FALSE; } bResult = DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &deviceNumber, sizeof(deviceNumber), &dwBytesReturned, NULL); CloseHandle(hDisk); if(!bResult){ return FALSE; } if(HarddiskNumberOut){ *HarddiskNumberOut = deviceNumber.DeviceNumber; } return TRUE; }