LPSTR pReadEulaFromFile( MSIHANDLE hInstall) { XTL::AutoProcessHeapPtr<TCHAR> sourceDir; UINT ret = pMsiGetProperty(hInstall, _T("SourceDir"), &sourceDir, NULL); if (ERROR_SUCCESS != ret) { pMsiLogMessage( hInstall, _T("EULACA: MsiGetProperty(SourceDir) failed, error=0x%X"), ret); return NULL; } // // EULA from the property EulaFileName // XTL::AutoProcessHeapPtr<CHAR> eulaText = pReadEulaFromFileEx(hInstall, sourceDir, _T("EulaFileName")); if (NULL == static_cast<LPSTR>(eulaText)) { // // try again with EulaFallbackFileName // eulaText = pReadEulaFromFileEx( hInstall, sourceDir, _T("EulaFallbackFileName")); if (NULL == static_cast<LPSTR>(eulaText)) { // // Once more with EulaFallbackFileName2 // eulaText = pReadEulaFromFileEx( hInstall, sourceDir, _T("EulaFallbackFileName2")); } } // // If eulaText is still NULL, every attempt has been failed. // if (NULL == static_cast<LPSTR>(eulaText)) { pMsiLogMessage( hInstall, _T("EULACA: EULA files are not available!")); return NULL; } // // Now we have the EULA Text! // return eulaText.Detach(); }
NDASVOL_LINKAGE HRESULT NDASVOL_CALL NdasIsNdasPathA( IN LPCSTR FilePath) { if (IsBadStringPtrA(FilePath, UINT_PTR(-1))) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "Invalid path, path=%hs\n", FilePath); return E_INVALIDARG; } XTLTRACE2(NdasVolTrace, 4, "NdasIsNdasPathA(%hs)\n", FilePath); int nChars = MultiByteToWideChar(CP_ACP, 0, FilePath, -1, NULL, 0); ++nChars; // additional terminating NULL char XTL::AutoProcessHeapPtr<WCHAR> wszFilePath = reinterpret_cast<LPWSTR>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nChars * sizeof(WCHAR))); if (wszFilePath.IsInvalid()) { return E_OUTOFMEMORY; } nChars = MultiByteToWideChar(CP_ACP, 0, FilePath, -1, wszFilePath, nChars); XTLASSERT(nChars > 0); return NdasIsNdasPathW(wszFilePath); }
LPSTR pReadEulaFromFileEx( MSIHANDLE hInstall, LPCTSTR SourceDir, LPCTSTR PropertyName) { TCHAR fullPath[MAX_PATH]; XTL::AutoProcessHeapPtr<TCHAR> eulaFileName; UINT ret = pMsiGetProperty(hInstall, PropertyName, &eulaFileName, NULL); if (ERROR_SUCCESS != ret) { pMsiLogMessage( hInstall, _T("EULACA: MsiGetProperty(%s) failed, error=0x%X"), PropertyName, ret); return NULL; } StringCchCopy(fullPath, MAX_PATH, SourceDir); StringCchCat(fullPath, MAX_PATH, eulaFileName); pMsiLogMessage( hInstall, _T("EULACA: EulaFile=%s"), fullPath); // // RTF file is an ANSI text file not unicode. // RTF has the CodePage tag inside, so we don't have to // worry about displaying non-English text. // XTL::AutoProcessHeapPtr<CHAR> eulaText = pReadTextFromFile(fullPath); if (NULL == (LPSTR) eulaText) { pMsiLogMessage( hInstall, _T("EULACA: ReadTextFromFile(%s) failed, error=0x%X"), fullPath, GetLastError()); return NULL; } pMsiLogMessage( hInstall, _T("EULACA: Read EULA text from %s"), fullPath); return eulaText.Detach(); }
LPSTR pReadTextFromFile( LPCTSTR szFileName) { XTL::AutoFileHandle hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == static_cast<HANDLE>(hFile)) { return NULL; } LARGE_INTEGER fileSize; BOOL fSuccess = GetFileSizeEx(hFile, &fileSize); if (!fSuccess) { return NULL; } DWORD cbToRead = fileSize.LowPart; XTL::AutoProcessHeapPtr<CHAR> lpBuffer = (LPSTR) ::HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, cbToRead); if (NULL == static_cast<LPSTR>(lpBuffer)) { return NULL; } DWORD cbRead; fSuccess = ReadFile( hFile, lpBuffer, cbToRead, &cbRead, NULL); if (!fSuccess) { return NULL; } return lpBuffer.Detach(); }
NDASVOL_LINKAGE BOOL NDASVOL_CALL NdasIsNdasPathW( IN LPCWSTR FilePath) { CPARAM(IsValidStringPtrW(FilePath, UINT_PTR(-1))); XTLTRACE2(NdasVolTrace, 4, "NdasIsNdasPathW(%ls)\n", FilePath); XTL::AutoProcessHeapPtr<TCHAR> mountPoint = pGetVolumeMountPointForPath(FilePath); if (mountPoint.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, _T("pGetVolumeMountPointForPath(%s) failed, error=0x%X\n"), FilePath, GetLastError()); return FALSE; } XTL::AutoProcessHeapPtr<TCHAR> volumeName = pGetVolumeDeviceNameForMountPoint(mountPoint); if (volumeName.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, _T("pGetVolumeDeviceNameForMountPoint(%s) failed, error=0x%X\n"), mountPoint, GetLastError()); return FALSE; } // Volume is a \\.\C: XTL::AutoFileHandle hVolume = ::CreateFileW( volumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hVolume.IsInvalid()) { return FALSE; } return NdasIsNdasVolume(hVolume); }
PSTORAGE_DESCRIPTOR_HEADER pStorageQueryProperty( HANDLE hDevice, STORAGE_PROPERTY_ID PropertyId, STORAGE_QUERY_TYPE QueryType) { STORAGE_PROPERTY_QUERY spquery; ::ZeroMemory(&spquery, sizeof(spquery)); spquery.PropertyId = PropertyId; spquery.QueryType = QueryType; DWORD bufferLength = sizeof(STORAGE_DESCRIPTOR_HEADER); XTL::AutoProcessHeapPtr<STORAGE_DESCRIPTOR_HEADER> buffer = static_cast<STORAGE_DESCRIPTOR_HEADER*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength)); if (buffer.IsInvalid()) { return NULL; } DWORD returnedLength; BOOL fSuccess = ::DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spquery, sizeof(spquery), buffer, bufferLength, &returnedLength, NULL); if (!fSuccess) { XTLTRACE_ERR("IOCTL_STORAGE_QUERY_PROPERTY(HEADER) failed.\n"); return NULL; } // We only retrived the header, now we reallocate the buffer // required for the actual query bufferLength = buffer->Size; XTL::AutoProcessHeapPtr<STORAGE_DESCRIPTOR_HEADER> newBuffer = static_cast<STORAGE_DESCRIPTOR_HEADER*>( ::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, bufferLength)); if (newBuffer.IsInvalid()) { return NULL; } // set the buffer with the new buffer buffer.Detach(); buffer = newBuffer.Detach(); // now we can query the actual property with the proper size fSuccess = ::DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spquery, sizeof(spquery), buffer, bufferLength, &returnedLength, NULL); if (!fSuccess) { XTLTRACE_ERR("IOCTL_STORAGE_QUERY_PROPERTY(DATA) failed.\n"); return NULL; } return buffer.Detach(); }
HRESULT pGetVolumeMountPointForPathW( __in LPCWSTR Path, __out LPWSTR* MountPoint) { if (NULL == MountPoint) { return E_POINTER; } *MountPoint = NULL; // TODO: It is possible to be the path is more than MAX_PATH // in case of supporting unicode file names up to 65534 DWORD mountPointLength = MAX_PATH; XTL::AutoProcessHeapPtr<TCHAR> mountPoint = static_cast<TCHAR*>( ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, mountPointLength * sizeof(WCHAR))); if (mountPoint.IsInvalid()) { return E_OUTOFMEMORY; } if (!GetVolumePathName(Path, mountPoint, mountPointLength)) { HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "GetVolumePathName(%ls) failed, hr=0x%X\n", Path, hr); return hr; } XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, "Path(%ls) is mounted from %s.\n", Path, mountPoint); *MountPoint = mountPoint.Detach(); return S_OK; }
LPTSTR pGetVolumeInstIdListForDisk( LPCTSTR DiskInstId) { // Disk and volumes are removal relations. XTL::AutoProcessHeapPtr<TCHAR> VolumeInstIdList; CONFIGRET ret = pCMGetDeviceIDList( &VolumeInstIdList, DiskInstId, CM_GETIDLIST_FILTER_REMOVALRELATIONS); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pCMGetDeviceIDList failed, cret=0x%X\n", ret); ::SetLastError(ConfigRetToWin32Error(ret)); return NULL; } return VolumeInstIdList.Detach(); }
LPTSTR pGetDeviceSymbolicLinkList( LPCGUID InterfaceClassGuid, DEVINSTID DevInstId, ULONG Flags /*= CM_GET_DEVICE_INTERFACE_LIST_PRESENT*/) { XTL::AutoProcessHeapPtr<TCHAR> SymbolicLinkList; CONFIGRET ret = pCMGetDeviceInterfaceList( &SymbolicLinkList, const_cast<LPGUID>(InterfaceClassGuid), DevInstId, Flags); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pCMGetDeviceInterfaceList failed, cret=0x%X\n", ret); ::SetLastError(ConfigRetToWin32Error(ret)); return NULL; } return SymbolicLinkList.Detach(); }
// // Returns the symbolic link name of the disk. // // Caller should free the non-null returned pointer // with HeapFree(GetProcessHeap(),...) // LPTSTR pGetChildDevInstIdsForNdasScsiLocation( const NDAS_SCSI_LOCATION* NdasScsiLocation) { DEVINST NdasScsiDevInst; if (!pFindNdasScsiDevInst(&NdasScsiDevInst, NdasScsiLocation->SlotNo)) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "FindNdasScsiDevInst failed, error=0x%X\n", GetLastError()); return NULL; } TCHAR NdasScsiInstanceId[MAX_DEVICE_ID_LEN]; CONFIGRET ret = ::CM_Get_Device_ID( NdasScsiDevInst, NdasScsiInstanceId, RTL_NUMBER_OF(NdasScsiInstanceId), 0); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Get_Device_ID failed, cret=0x%X\n", ret); return NULL; } XTL::AutoProcessHeapPtr<TCHAR> ChildDevInstIdList; ret = pCMGetDeviceIDList( &ChildDevInstIdList, NdasScsiInstanceId, CM_GETIDLIST_FILTER_BUSRELATIONS); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pCMGetDeviceIDList failed, cret=0x%X\n", ret); ::SetLastError(ConfigRetToWin32Error(ret)); return NULL; } return ChildDevInstIdList.Detach(); }
LPTSTR pMsiGetSourcePath( MSIHANDLE hInstall, LPCTSTR szFolder, LPDWORD pcch) { XTL::AutoProcessHeapPtr<TCHAR> pszValue; DWORD cchValue = 0; UINT msiret = MsiGetSourcePath(hInstall, szFolder, _T(""), &cchValue); if (ERROR_MORE_DATA == msiret) { ++cchValue; pszValue = (LPTSTR) HeapAlloc( GetProcessHeap(), 0, cchValue * sizeof(TCHAR)); if (NULL == (LPTSTR) pszValue) { return NULL; } msiret = MsiGetSourcePath(hInstall, szFolder, pszValue, &cchValue); } if (ERROR_SUCCESS != msiret) { return NULL; } if (NULL != pcch) { *pcch = cchValue; } return pszValue.Detach(); }
LPTSTR pMsiGetProperty( MSIHANDLE hInstall, LPCTSTR szPropertyName, LPDWORD pcch) { HANDLE hHeap = ::GetProcessHeap(); XTL::AutoProcessHeapPtr<TCHAR> pszValue; DWORD cchValue = 0; UINT msiret = MsiGetProperty(hInstall, szPropertyName, _T(""), &cchValue); if (ERROR_SUCCESS != msiret && ERROR_MORE_DATA != msiret) { return NULL; } if (ERROR_MORE_DATA == msiret) { ++cchValue; pszValue = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, cchValue * sizeof(TCHAR)); if (NULL == (LPTSTR) pszValue) { return NULL; } msiret = MsiGetProperty(hInstall, szPropertyName, pszValue, &cchValue); if (ERROR_SUCCESS != msiret) { return NULL; } } if (NULL != pcch) { *pcch = cchValue; } return pszValue.Detach(); }
NDASVOL_LINKAGE BOOL NDASVOL_CALL NdasIsNdasPathA( IN LPCSTR FilePath) { CPARAM(IsValidStringPtrA(FilePath, UINT_PTR(-1))); XTLTRACE2(NdasVolTrace, 4, "NdasIsNdasPathA(%hs)\n", FilePath); int nChars = ::MultiByteToWideChar(CP_ACP, 0, FilePath, -1, NULL, 0); ++nChars; // additional terminating NULL char XTL::AutoProcessHeapPtr<WCHAR> wszFilePath = reinterpret_cast<LPWSTR>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nChars * sizeof(WCHAR))); if (wszFilePath.IsInvalid()) { ::SetLastError(ERROR_OUTOFMEMORY); return FALSE; } nChars = ::MultiByteToWideChar(CP_ACP, 0, FilePath, -1, wszFilePath, nChars); return NdasIsNdasPathW(wszFilePath); }
PDRIVE_LAYOUT_INFORMATION_EX pDiskGetDriveLayoutEx(HANDLE hDevice) { DWORD returnedLength; // always returns 0 DWORD bufferLength = sizeof(DRIVE_LAYOUT_INFORMATION_EX); XTL::AutoProcessHeapPtr<DRIVE_LAYOUT_INFORMATION_EX> buffer = static_cast<DRIVE_LAYOUT_INFORMATION_EX*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength)); BOOL fSuccess = ::DeviceIoControl( hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buffer, bufferLength, &returnedLength, NULL); while (!fSuccess && ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) { // To determine the size of output buffer that is required, caller // should send this IOCTL request in a loop. Every time the // storage stack rejects the IOCTL with an error message // indicating that the buffer was too small, caller should double // the buffer size. bufferLength += bufferLength; XTL::AutoProcessHeapPtr<DRIVE_LAYOUT_INFORMATION_EX> newBuffer = static_cast<DRIVE_LAYOUT_INFORMATION_EX*>( ::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, bufferLength)); if (newBuffer.IsInvalid()) { // buffer is still valid in case of failure // buffer will be released on return. return NULL; } // buffer points to the non-valid memory, so invalidate it now buffer.Detach(); // transfer the data from newBuffer to buffer buffer = newBuffer.Detach(); // query again fSuccess = ::DeviceIoControl( hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buffer, bufferLength, &returnedLength, NULL); } // returns the buffer return buffer.Detach(); }
LPTSTR pGetDiskForNdasScsiLocationEx( const NDAS_SCSI_LOCATION* NdasScsiLocation, BOOL SymbolicLinkOrDevInstId) { // Get the child device instances of the NDAS SCSI pdo XTL::AutoProcessHeapPtr<TCHAR> ChildDevInstIdList = pGetChildDevInstIdsForNdasScsiLocation(NdasScsiLocation); // Find the disk of TargetID and LUN for all child device instances for (LPCTSTR ChildDevInstId = ChildDevInstIdList; ChildDevInstId && *ChildDevInstId; ChildDevInstId += ::lstrlen(ChildDevInstId) + 1) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_VERBOSE, _T("ChildDevInstId:%s\n"), ChildDevInstId); // Ensure that the child really is present (not ghosted) DEVINST ChildDevInst; CONFIGRET ret = ::CM_Locate_DevNode( &ChildDevInst, const_cast<DEVINSTID>(ChildDevInstId), CM_LOCATE_DEVNODE_NORMAL); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Locate_DevNode failed, cret=0x%X\n", ret); continue; } // Query the Disk Class Interface, if there are no disk class // interface, it is not of a disk class. XTL::AutoProcessHeapPtr<TCHAR> SymLinkList; ret = pCMGetDeviceInterfaceList( &SymLinkList, &DiskClassGuid, const_cast<DEVINSTID>(ChildDevInstId), CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pCMGetDeviceInterfaceList failed, cret=0x%X\n", ret); continue; } // Returned list contains the list of the device file names (or // symbolic links) which we can open with CreateFile for IO_CTLs for (LPCTSTR DeviceName = SymLinkList; DeviceName && *DeviceName; DeviceName += ::lstrlen(DeviceName) + 1) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_VERBOSE, _T("Device:%s\n"), DeviceName); XTL::AutoFileHandle hDevice = ::CreateFile( DeviceName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, _T("CreateFile(%s) failed, error=0x%X\n"), DeviceName, GetLastError()); continue; } // Query the SCSI Address and compare TargetID and LUN to // compare them with those of NDAS SCSI location. SCSI_ADDRESS scsiAddress; if (!pScsiGetAddress(hDevice, &scsiAddress)) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, _T("GetScsiAddress(%s) failed, error=0x%X\n"), DeviceName, GetLastError()); continue; } if (NdasScsiLocation->TargetID == scsiAddress.TargetId && NdasScsiLocation->LUN == scsiAddress.Lun) { // We found the target disk, and we create a buffer to // return. If SymbolicLinkOrDevInstId is non-zero (TRUE), // we will returns SymbolicLink, otherwise, we will return the DevInstId if (SymbolicLinkOrDevInstId) { DWORD TargetLength = (::lstrlen(DeviceName) + 1) * sizeof(TCHAR); XTL::AutoProcessHeapPtr<TCHAR> TargetDeviceName = static_cast<LPTSTR>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, TargetLength)); if (TargetDeviceName.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "HeapAlloc failed, byets=%d\n", TargetLength); return NULL; } ::CopyMemory(TargetDeviceName, DeviceName, TargetLength); return TargetDeviceName.Detach(); } else { DWORD TargetLength = (::lstrlen(ChildDevInstId) + 1) * sizeof(TCHAR); XTL::AutoProcessHeapPtr<TCHAR> TargetDevInstId = static_cast<LPTSTR>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, TargetLength)); if (TargetDevInstId.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "HeapAlloc failed, byets=%d\n", TargetLength); return NULL; } ::CopyMemory(TargetDevInstId, ChildDevInstId, TargetLength); return TargetDevInstId.Detach(); } } } } return NULL; }
CONFIGRET pCMGetDeviceIDList( LPTSTR* RelDevInstIdList, LPCTSTR DevInstId, ULONG Flags) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("DevInstId=%s,Flags=%08X\n"), DevInstId, Flags); *RelDevInstIdList = NULL; ULONG bufferLength; CONFIGRET ret = ::CM_Get_Device_ID_List_Size( &bufferLength, DevInstId, Flags); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Get_Device_ID_List_Size failed with cret=0x%X.\n", ret); return ret; } XTLTRACE2(NdasVolTrace, TRACE_LEVEL_VERBOSE, "RequiredBufferSize=%d chars\n", bufferLength); if (0 == bufferLength) { TCHAR* empty = static_cast<TCHAR*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * sizeof(TCHAR))); *RelDevInstIdList = empty; return CR_SUCCESS; } XTL::AutoProcessHeapPtr<TCHAR> buffer = static_cast<TCHAR*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength * sizeof(TCHAR))); if (buffer.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "HeapAlloc failed, bytes=%d\n", bufferLength * sizeof(TCHAR)); return CR_OUT_OF_MEMORY; } ret = ::CM_Get_Device_ID_List( DevInstId, buffer, bufferLength, Flags); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Get_Device_ID_List failed with cret=0x%X.\n", ret); return ret; } *RelDevInstIdList = buffer.Detach(); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("RelDevInstIdList=%s\n"), *RelDevInstIdList); return CR_SUCCESS; }
HRESULT pGetVolumeDeviceNameForMountPointW( __in LPCWSTR VolumeMountPoint, __out LPWSTR* VolumeDeviceName) { // The lpszVolumeMountPoint parameter may be a drive letter with // appended backslash (\), such as "D:\". Alternatively, it may be // a path to a volume mount point, again with appended backslash (\), // such as "c:\mnt\edrive\". // A reasonable size for the buffer to accommodate the largest possible // volume name is 50 characters --> wrong 100 HRESULT hr; XTLASSERT(NULL != VolumeDeviceName); if (NULL == VolumeDeviceName) { return E_POINTER; } *VolumeDeviceName = NULL; const DWORD MAX_VOLUMENAME_LEN = 50; DWORD volumeDeviceNameLength = MAX_VOLUMENAME_LEN; XTL::AutoProcessHeapPtr<TCHAR> volumeDeviceName = static_cast<TCHAR*>( HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, volumeDeviceNameLength * sizeof(TCHAR))); if (volumeDeviceName.IsInvalid()) { XTLTRACE2(NdasVolTrace, 0, "HeapAlloc for %d bytes failed.\n", volumeDeviceNameLength); return E_OUTOFMEMORY; } BOOL success = GetVolumeNameForVolumeMountPoint( VolumeMountPoint, volumeDeviceName, volumeDeviceNameLength); if (!success) { hr = HRESULT_FROM_WIN32(GetLastError()); XTLTRACE2(NdasVolTrace, 0, "GetVolumeNameForVolumeMountPoint(%ls) failed, hr=0x%X\n", VolumeMountPoint, hr); return hr; } // Volume Name is a format of \\?\Volume{XXXX}\ with trailing backslash // Volume device name is that of \\.\Volume{XXXX} without trailing backslash _ASSERTE(_T('\\') == volumeDeviceName[0]); _ASSERTE(_T('\\') == volumeDeviceName[1]); _ASSERTE(_T('?') == volumeDeviceName[2]); _ASSERTE(_T('\\') == volumeDeviceName[3]); if (_T('\\') == volumeDeviceName[0] && _T('\\') == volumeDeviceName[1] && _T('?') == volumeDeviceName[2] && _T('\\') == volumeDeviceName[3]) { // replace ? to . volumeDeviceName[2] = _T('.'); } // remove trailing backslash pRemoveTrailingBackslash(volumeDeviceName); XTLTRACE2(NdasVolTrace, 2, "VolumeMountPoint(%ls)=>Volume(%ls)\n", VolumeMountPoint, volumeDeviceName); *VolumeDeviceName = volumeDeviceName.Detach(); return S_OK; }
HRESULT pIsVolumeSpanningNdasDevice( __in HANDLE hVolume) { HRESULT hr; XTL::AutoProcessHeapPtr<VOLUME_DISK_EXTENTS> extents = pVolumeGetVolumeDiskExtents(hVolume); if (extents.IsInvalid()) { hr = HRESULT_FROM_WIN32(GetLastError()); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, hr=0x%X\n", hr); return hr; } for (DWORD i = 0; i < extents->NumberOfDiskExtents; ++i) { const DISK_EXTENT* diskExtent = &extents->Extents[i]; XTLTRACE2(NdasVolTrace, 2, "Disk Number=%d\n", diskExtent->DiskNumber); DWORD ndasSlotNumber; hr = pGetNdasSlotNumberFromDiskNumber( diskExtent->DiskNumber, &ndasSlotNumber); if (FAILED(hr)) { SCSI_ADDRESS scsiAddress = {0}; // // Since Windows Server 2003, SCSIPORT PDO does not send // IOCTL_SCSI_MINIPORT down to the stack. Hence we should send // the IOCTL directly to SCSI controller. // XTLTRACE2(NdasVolTrace, 2, "PhysicalDrive%d does not seem to an NDAS SCSI. Try with the adapter\n", diskExtent->DiskNumber); hr = pGetScsiAddressForDiskNumber( diskExtent->DiskNumber, &scsiAddress); if (FAILED(hr)) { XTLTRACE2(NdasVolTrace, 1, "Disk %d does not seem to be attached to the SCSI controller.\n", diskExtent->DiskNumber); continue; } XTLTRACE2(NdasVolTrace, 2, "SCSI Address (PortNumber=%d,PathId=%d,TargetId=%d,LUN=%d)\n", scsiAddress.PortNumber, scsiAddress.PathId, scsiAddress.TargetId, scsiAddress.Lun); DWORD ndasSlotNumber; hr = pGetNdasSlotNumberForScsiPortNumber( scsiAddress.PortNumber, &ndasSlotNumber); if (FAILED(hr)) { XTLTRACE2(NdasVolTrace, 2, "ScsiPort %d does not seem to an NDAS SCSI.\n", scsiAddress.PortNumber); continue; } } XTLTRACE2(NdasVolTrace, 2, "Detected Disk %d/%d has a NDAS Slot Number=%d (first found only).\n", i + 1, extents->NumberOfDiskExtents, ndasSlotNumber); return S_OK; } return E_FAIL; }
// // Returns the symbolic link name list of the volume. // Each entry is null-terminated and the last entry is terminated // by an additional null character // // Caller should free the non-null returned pointer // with HeapFree(GetProcessHeap(),...) // LPTSTR pGetVolumesForNdasScsiLocation( const NDAS_SCSI_LOCATION* NdasScsiLocation) { // Get the disk instance id of the location XTL::AutoProcessHeapPtr<TCHAR> DiskInstId = pGetDiskForNdasScsiLocationEx(NdasScsiLocation, FALSE); if (DiskInstId.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "GetDiskDevInstId failed, error=0x%X\n", GetLastError()); return NULL; } // Get the volume instance id list of the disk XTL::AutoProcessHeapPtr<TCHAR> VolumeInstIdList = pGetVolumeInstIdListForDisk(DiskInstId); if (VolumeInstIdList.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "GetVolumeInstIdList failed, error=0x%X\n", GetLastError()); return NULL; } // Get the volume names of the disk (via interface query) // Preallocate the buffer up to MAX_PATH DWORD bufferLength = MAX_PATH * sizeof(TCHAR); DWORD bufferRemaining = bufferLength; XTL::AutoProcessHeapPtr<TCHAR> buffer = static_cast<LPTSTR>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength)); LPTSTR bufferNext = static_cast<LPTSTR>(buffer); // direct resource access (non-const) for (LPCTSTR VolumeInstId = VolumeInstIdList; VolumeInstId && *VolumeInstId; VolumeInstId += ::lstrlen(VolumeInstId) + 1) { // Actually returned buffer is a list of null-terminated strings // but we queried for a specific instance id and for the specific // class, where only one or zero volume name may return. // So the return type is just a single string. XTL::AutoProcessHeapPtr<TCHAR> VolumeName = pGetDeviceSymbolicLinkList( &GUID_DEVINTERFACE_VOLUME, const_cast<LPTSTR>(VolumeInstId), CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (VolumeName.IsInvalid()) { // may not be a volume XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("%s is not a volume device\n"), VolumeInstId); continue; } for (LPCTSTR VN = VolumeName; VN && *VN; VN += ::lstrlen(VN) + 1) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("VolumeName=%s\n"), VN); } XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("VolumeName=%s\n"), VolumeName); DWORD volumeNameLength = ::lstrlen(VolumeName); DWORD bufferRequired = (volumeNameLength + 1) * sizeof(TCHAR); if (bufferRemaining < bufferRequired) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, "Reallocation\n"); XTL::AutoProcessHeapPtr<TCHAR> newBuffer = static_cast<LPTSTR>( ::HeapReAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, bufferLength + bufferRequired - bufferRemaining)); if (newBuffer.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "HeapReAlloc failed, bytes=%d\n", bufferLength + bufferLength - bufferRemaining); return NULL; } size_t bufferNextOffset = reinterpret_cast<BYTE*>(bufferNext) - reinterpret_cast<BYTE*>(*(&buffer)); // discard the old buffer and attach it to the new buffer buffer.Detach(); buffer = newBuffer.Detach(); bufferNext = reinterpret_cast<TCHAR*>( reinterpret_cast<BYTE*>(static_cast<LPTSTR>(buffer)) + bufferNextOffset); } ::CopyMemory(bufferNext, VolumeName, bufferRequired); bufferNext += volumeNameLength + 1; bufferRemaining -= bufferRequired; } return buffer.Detach(); }
NDASVOL_LINKAGE BOOL NDASVOL_CALL NdasEnumNdasScsiLocationsForVolume( IN HANDLE hVolume, NDASSCSILOCATIONENUMPROC EnumProc, LPVOID Context) { CPARAM(!::IsBadCodePtr((FARPROC)EnumProc)); XTL::AutoProcessHeapPtr<VOLUME_DISK_EXTENTS> extents = pVolumeGetVolumeDiskExtents(hVolume); if (extents.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error=0x%X\n", GetLastError()); return FALSE; } for (DWORD i = 0; i < extents->NumberOfDiskExtents; ++i) { const DISK_EXTENT* diskExtent = &extents->Extents[i]; SCSI_ADDRESS scsiAddress = {0}; if (!pGetScsiAddressForDiskNumber(diskExtent->DiskNumber, &scsiAddress)) { XTLTRACE2(NdasVolTrace, 1, "Disk %d does not seem to be attached to the SCSI controller.\n", diskExtent->DiskNumber); continue; } XTLTRACE2(NdasVolTrace, 2, "SCSI Address (PortNumber=%d,PathId=%d,TargetId=%d,LUN=%d)\n", scsiAddress.PortNumber, scsiAddress.PathId, scsiAddress.TargetId, scsiAddress.Lun); DWORD ndasSlotNumber; if (!pGetNdasSlotNumberForScsiPortNumber(scsiAddress.PortNumber, &ndasSlotNumber)) { XTLTRACE2(NdasVolTrace, 2, "ScsiPort %d does not seem to an NDAS SCSI.\n", scsiAddress.PortNumber); continue; } XTLTRACE2(NdasVolTrace, 2, "Detected Disk %d/%d has NDAS Slot Number=%d (first found only).\n", i, extents->NumberOfDiskExtents, ndasSlotNumber); NDAS_SCSI_LOCATION ndasScsiLocation = {0}; ndasScsiLocation.SlotNo = ndasSlotNumber; ndasScsiLocation.TargetID = scsiAddress.TargetId; ndasScsiLocation.LUN = scsiAddress.Lun; BOOL fContinue = EnumProc(&ndasScsiLocation, Context); if (!fContinue) { return TRUE; } } return TRUE; }
CNdasUnitDevice* CNdasUnitDeviceCreator::CreateUnitDiskDevice() { // // Read DIB // // Read DIB should success, even if the unit disk does not contain // the DIB. If it fails, there should be some communication error. // XTL::AutoProcessHeapPtr<NDAS_DIB_V2> pDIBv2; XTL::AutoProcessHeapPtr<BLOCK_ACCESS_CONTROL_LIST> pBACL; // // ReadDIB is to allocate pDIBv2 // BOOL fSuccess = ReadDIB(&pDIBv2); // attach to auto heap if (!fSuccess) { XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "ReadDIB failed, error=0x%X\n", GetLastError()); XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Creating unit disk device instance failed.\n"); return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_READ_FAILURE); } if(0 != pDIBv2->BACLSize) { fSuccess = ReadBACL(&pBACL, pDIBv2->BACLSize); if (!fSuccess) { XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "ReadBACL failed, error=0x%X\n", GetLastError()); XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Creating unit disk device instance failed.\n"); return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_READ_FAILURE); } } NDAS_UNITDEVICE_DISK_TYPE diskType = pGetNdasUnitDiskTypeFromDIBv2(pDIBv2); if (NDAS_UNITDEVICE_DISK_TYPE_UNKNOWN == diskType) { // // Error! Invalid media type // XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Media type in DIBv2 is invalid, mediaType=0x%X\n", pDIBv2->iMediaType); // // we should create generic unknown unit disk device // return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_UNKNOWN_LDTYPE); } // return NULL; LPVOID pAddTargetInfo = NULL; NDAS_RAID_META_DATA Rmd = {0}; if (NMT_RAID1 == pDIBv2->iMediaType || NMT_RAID4 == pDIBv2->iMediaType) { // // These types are not used anymore, however, // for compatibility reasons, we retain these codes // pAddTargetInfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NDAS_LURN_RAID_INFO_V1)); PNDAS_LURN_RAID_INFO_V1 raidInfo = static_cast<PNDAS_LURN_RAID_INFO_V1>(pAddTargetInfo); raidInfo->SectorsPerBit = pDIBv2->iSectorsPerBit; raidInfo->SectorBitmapStart = m_udinfo.SectorCount.QuadPart - 0x0f00; raidInfo->SectorInfo = m_udinfo.SectorCount.QuadPart - 0x0002; raidInfo->SectorLastWrittenSector = m_udinfo.SectorCount.QuadPart - 0x1000; } else if (NMT_RAID1R2 == pDIBv2->iMediaType || NMT_RAID4R2 == pDIBv2->iMediaType || NMT_RAID1R3 == pDIBv2->iMediaType || NMT_RAID4R3 == pDIBv2->iMediaType) { // // do not allocate with "new INFO_RAID" // destructor will delete with "HeapFree" // pAddTargetInfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NDAS_LURN_RAID_INFO_V2)); PNDAS_LURN_RAID_INFO_V2 pIR = reinterpret_cast<PNDAS_LURN_RAID_INFO_V2>(pAddTargetInfo); fSuccess = m_devComm.ReadDiskBlock( reinterpret_cast<PBYTE>(&Rmd), NDAS_BLOCK_LOCATION_RMD, 1); if (!fSuccess) { XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Reading RMD failed: "); XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Creating unit disk device instance failed.\n"); return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_READ_FAILURE); } if (Rmd.Signature != NDAS_RAID_META_DATA_SIGNATURE) { XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "RMD signature mismatch."); XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Creating unit disk device instance failed.\n"); return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_UNKNOWN_LDTYPE); } pIR->SectorsPerBit = pDIBv2->iSectorsPerBit; pIR->nSpareDisk = pDIBv2->nSpareCount; // To fix: Use RaidSetId and ConfigSetId from NdasOpGetRaidInfo ::CopyMemory(&pIR->RaidSetId, &Rmd.RaidSetId, sizeof(pIR->RaidSetId)); ::CopyMemory(&pIR->ConfigSetId, &Rmd.ConfigSetId, sizeof(pIR->ConfigSetId)); } UINT64 ulUserBlocks = static_cast<UINT64>(pDIBv2->sizeUserSpace); DWORD ldSequence = pDIBv2->iSequence; NDAS_LOGICALDEVICE_GROUP ldGroup = {0}; ldGroup.Type = pGetNdasLogicalDeviceTypeFromDIBv2(pDIBv2); ldGroup.nUnitDevices = pDIBv2->nDiskCount + pDIBv2->nSpareCount; ldGroup.nUnitDevicesSpare = pDIBv2->nSpareCount; // ::CopyMemory(&ldGroup.RaidSetId, &Rmd.RaidSetId, sizeof(GUID)); // ::CopyMemory(&ldGroup.ConfigSetId, &Rmd.ConfigSetId, sizeof(GUID)); for(DWORD i=0; i<MAX_NDAS_LOGICALDEVICE_GROUP_MEMBER; i++) { ldGroup.DeviceHwVersions[i] = pDIBv2->UnitDiskInfos[i].HwVersion; } // // Consistency check for DIB // // 1. DIB should contain an entry for this unit device // wich m_pDevice->GetDeviceId() and m_dwUnitNo; // // Otherwise, DIB is invalid and reported as Single // for(DWORD i = 0; i < ldGroup.nUnitDevices; i++) { CopyMemory( &ldGroup.UnitDevices[i].DeviceId, pDIBv2->UnitDisks[i].MACAddr, sizeof(NDAS_DEVICE_ID)); ldGroup.UnitDevices[i].UnitNo = pDIBv2->UnitDisks[i].UnitNumber; } // // Read CONTENT_ENCRYPT // // Read CONTENT_ENCRYPT should success, even if the unit disk does not contain // the CONTENT_ENCRYPT. If it fails, there should be some communication error. // NDAS_CONTENT_ENCRYPT_BLOCK ceb = {0}; NDAS_CONTENT_ENCRYPT ce = {0}; fSuccess = ReadContentEncryptBlock(&ceb); if (!fSuccess) { XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "ReadContentEncryptBlock failed, error=0x%X\n", GetLastError()); XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_ERROR, "Creating unit disk device instance failed.\n"); (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_CEB_READ_FAILURE); return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_READ_FAILURE); } UINT uiRet = ::NdasEncVerifyContentEncryptBlock(&ceb); if (NDASENC_ERROR_CEB_INVALID_SIGNATURE == uiRet) { // No Content Encryption // Safe to ignore ce.Method = NDAS_CONTENT_ENCRYPT_METHOD_NONE; } else if (NDASENC_ERROR_CEB_INVALID_CRC == uiRet) { // No Content Encryption // Safe to ignore ce.Method = NDAS_CONTENT_ENCRYPT_METHOD_NONE; } else if (NDASENC_ERROR_CEB_UNSUPPORTED_REVISION == uiRet) { // Error ! (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_CEB_UNSUPPORTED_REVISION, uiRet); // return NULL; return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_ECKEY_FAILURE); } else if (NDASENC_ERROR_CEB_INVALID_KEY_LENGTH == uiRet) { // No Content Encryption (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_CEB_INVALID_KEY_LENGTH, uiRet); ce.Method = NDAS_CONTENT_ENCRYPT_METHOD_NONE; } else if (ERROR_SUCCESS != uiRet) { // No Content Encryption ce.Method = NDAS_CONTENT_ENCRYPT_METHOD_NONE; } else { // // We consider the case that ENCRYPTION is not NONE. // if (NDAS_CONTENT_ENCRYPT_METHOD_NONE != ceb.Method) { BYTE SysKey[16] = {0}; DWORD cbSysKey = sizeof(SysKey); uiRet = ::NdasEncGetSysKey(cbSysKey, SysKey, &cbSysKey); if (ERROR_SUCCESS != uiRet) { (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_GET_SYS_KEY, uiRet); // return NULL; return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_ECKEY_FAILURE); } uiRet = ::NdasEncVerifyFingerprintCEB(SysKey, cbSysKey, &ceb); if (ERROR_SUCCESS != uiRet) { (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_SYS_KEY_MISMATCH, uiRet); // return NULL; return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_ECKEY_FAILURE); } // // Create Content Encrypt // ce.Method = ceb.Method; ce.KeyLength = ceb.KeyLength; ce.Key; uiRet = ::NdasEncCreateContentEncryptKey( SysKey, cbSysKey, ceb.Key, ceb.KeyLength, ce.Key, sizeof(ce.Key)); if (ERROR_SUCCESS != uiRet) { (VOID) ::NdasLogEventError2(EVT_NDASSVC_ERROR_KEY_GENERATION_FAILURE, uiRet); // return NULL; return _CreateUnknownUnitDiskDevice(NDAS_UNITDEVICE_ERROR_HDD_ECKEY_FAILURE); } } } CNdasUnitDiskDevice* pUnitDiskDevice = new CNdasUnitDiskDevice( m_pDevice, m_dwUnitNo, diskType, m_udinfo, ldGroup, ldSequence, ulUserBlocks, pAddTargetInfo, ce, pDIBv2, pBACL); if (NULL == pUnitDiskDevice) { return NULL; } // We should detach pDIBv2 from being freeed here // pUnitDiskDevice will take care of it at dtor pDIBv2.Detach(); pBACL.Detach(); return pUnitDiskDevice; }
NDASVOL_LINKAGE HRESULT NDASVOL_CALL NdasEnumNdasLocationsForVolume( IN HANDLE hVolume, NDASLOCATIONENUMPROC EnumProc, LPVOID Context) { HRESULT hr; if (IsBadCodePtr((FARPROC)EnumProc)) { return E_POINTER; } XTL::AutoProcessHeapPtr<VOLUME_DISK_EXTENTS> extents = pVolumeGetVolumeDiskExtents(hVolume); if (extents.IsInvalid()) { hr = HRESULT_FROM_WIN32(GetLastError()); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, hr=0x%x\n", hr); return hr; } for (DWORD i = 0; i < extents->NumberOfDiskExtents; ++i) { const DISK_EXTENT* diskExtent = &extents->Extents[i]; DWORD ndasSlotNumber; hr = pGetNdasSlotNumberFromDiskNumber( diskExtent->DiskNumber, &ndasSlotNumber); if (FAILED(hr)) { SCSI_ADDRESS scsiAddress = {0}; // // Since Windows Server 2003, SCSIPORT PDO does not send // IOCTL_SCSI_MINIPORT down to the stack. Hence we should send // the IOCTL directly to SCSI controller. // hr = pGetScsiAddressForDiskNumber( diskExtent->DiskNumber, &scsiAddress); if (FAILED(hr)) { XTLTRACE2(NdasVolTrace, 1, "Disk %d does not seem to be attached to the SCSI controller.\n", diskExtent->DiskNumber); continue; } XTLTRACE2(NdasVolTrace, 2, "SCSI Address (PortNumber=%d,PathId=%d,TargetId=%d,LUN=%d)\n", scsiAddress.PortNumber, scsiAddress.PathId, scsiAddress.TargetId, scsiAddress.Lun); hr = pGetNdasSlotNumberForScsiPortNumber( scsiAddress.PortNumber, &ndasSlotNumber); if (FAILED(hr)) { XTLTRACE2(NdasVolTrace, 2, "ScsiPort %d does not seem to an NDAS SCSI.\n", scsiAddress.PortNumber); continue; } } XTLTRACE2(NdasVolTrace, 2, "Detected Disk %d/%d has NDAS Slot Number=%d (first found only).\n", i, extents->NumberOfDiskExtents, ndasSlotNumber); NDAS_LOCATION ndasScsiLocation = ndasSlotNumber; // // EnumProc // S_OK: continue enumeration // S_FALSE: returns S_OK to the caller (stop enumeration) // otherwise E_XXX: returns E_XXX to the caller // hr = EnumProc(ndasScsiLocation, Context); if (FAILED(hr)) { return hr; } else if (S_FALSE == hr) { return S_OK; } } return S_OK; }
HRESULT pGetScsiAddressForDisk( __in HANDLE hDisk, __out PSCSI_ADDRESS ScsiAddress) { HRESULT hr; // // Query Storage Property // XTLTRACE2(NdasVolTrace, 3, "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)\n"); if (NULL == ScsiAddress) { return E_POINTER; } XTL::AutoProcessHeapPtr<STORAGE_ADAPTER_DESCRIPTOR> adapterDescriptor = pStorageQueryAdapterProperty(hDisk); if (adapterDescriptor.IsInvalid()) { hr = HRESULT_FROM_WIN32(GetLastError()); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pStorageQueryAdapterProperty failed, hr=0x%X\n", hr); return hr; } // // Ignore non-SCSI device // if (BusTypeScsi != adapterDescriptor->BusType) { hr = NDASVOL_ERROR_NON_NDAS_VOLUME; XTLTRACE2(NdasVolTrace, 2, "Ignoring non-scsi bus, hr=0x%X\n", hr); return hr; } // // Query SCSI Address, given that the physical drive is a SCSI device // XTLTRACE2(NdasVolTrace, 3, "DeviceIoControl(IOCTL_SCSI_GET_ADDRESS)\n"); SCSI_ADDRESS scsiAddress = {0}; hr = pScsiGetAddress(hDisk, &scsiAddress); if (FAILED(hr)) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "pScsiGetAddress failed, hr=0x%X\n", hr); hr = NDASVOL_ERROR_NON_NDAS_VOLUME; return hr; } XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, "SCSIAddress: Len: %d, PortNumber: %d, " "PathId: %d, TargetId: %d, Lun: %d\n", (DWORD) scsiAddress.Length, (DWORD) scsiAddress.PortNumber, (DWORD) scsiAddress.PathId, (DWORD) scsiAddress.TargetId, (DWORD) scsiAddress.Lun); // // Return the result // *ScsiAddress = scsiAddress; return S_OK; }
CONFIGRET pCMGetDeviceInterfaceList( LPTSTR* SymbolicLinkNameList, LPCGUID InterfaceClassGuid, DEVINSTID DevInstId, ULONG Flags /*= CM_GET_DEVICE_INTERFACE_LIST_PRESENT*/) { *SymbolicLinkNameList = NULL; ULONG bufferLength; CONFIGRET ret = ::CM_Get_Device_Interface_List_Size( &bufferLength, const_cast<LPGUID>(InterfaceClassGuid), DevInstId, Flags); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Get_Device_Interface_List_Size failed, cret=0x%X.\n", ret); return ret; } XTLTRACE2(NdasVolTrace, TRACE_LEVEL_VERBOSE, "RequiredBufferSize=%d chars\n", bufferLength); if (0 == bufferLength) { TCHAR* empty = static_cast<TCHAR*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * sizeof(TCHAR))); *SymbolicLinkNameList = empty; return CR_SUCCESS; } XTL::AutoProcessHeapPtr<TCHAR> buffer = static_cast<TCHAR*>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength * sizeof(TCHAR))); if (buffer.IsInvalid()) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "HeapAlloc failed, bytes=%d\n", bufferLength * sizeof(TCHAR)); return CR_OUT_OF_MEMORY; } ret = ::CM_Get_Device_Interface_List( const_cast<LPGUID>(InterfaceClassGuid), DevInstId, buffer, bufferLength, Flags); if (CR_SUCCESS != ret) { XTLTRACE2(NdasVolTrace, TRACE_LEVEL_ERROR, "CM_Get_Device_Interface_List failed, cret=%x.\n", ret); return ret; } *SymbolicLinkNameList = buffer.Detach(); XTLTRACE2(NdasVolTrace, TRACE_LEVEL_INFORMATION, _T("SymbolicLinkNameList=%s\n"), *SymbolicLinkNameList); return CR_SUCCESS; }
PVOLUME_DISK_EXTENTS pVolumeGetVolumeDiskExtents( HANDLE hVolume) { DWORD returnedLength; DWORD bufferLength = sizeof(VOLUME_DISK_EXTENTS); XTL::AutoProcessHeapPtr<VOLUME_DISK_EXTENTS> buffer = static_cast<PVOLUME_DISK_EXTENTS>( ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, bufferLength)); if (buffer.IsInvalid()) { XTLTRACE2_ERR(NdasVolTrace, 0, "HeapAlloc (%d bytes) failed.\n", bufferLength); return NULL; } BOOL fSuccess = ::DeviceIoControl( hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, buffer, bufferLength, &returnedLength, NULL); if (!fSuccess && ERROR_MORE_DATA == ::GetLastError()) { // // An extent is a contiguous run of sectors on one disk. When the // number of extents returned is greater than one (1), the error // code ERROR_MORE_DATA is returned. You should call // DeviceIoControl again, allocating enough buffer space based on // // the value of NumberOfDiskExtents after the first DeviceIoControl call. bufferLength = sizeof(VOLUME_DISK_EXTENTS) - sizeof(DISK_EXTENT) + sizeof(DISK_EXTENT) * buffer->NumberOfDiskExtents; XTL::AutoProcessHeapPtr<VOLUME_DISK_EXTENTS> newBuffer = static_cast<PVOLUME_DISK_EXTENTS>( ::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, bufferLength)); if (newBuffer.IsInvalid()) { // buffer is still valid in case of failure // buffer will be released on return. XTLTRACE2_ERR(NdasVolTrace, 0, "HeapReAlloc (%d bytes) failed.\n", bufferLength); return NULL; } // buffer points to the non-valid memory, so invalidate it now buffer.Detach(); // transfer the data from newBuffer to buffer buffer = newBuffer.Detach(); // query again fSuccess = ::DeviceIoControl( hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, buffer, bufferLength, &returnedLength, NULL); } if (!fSuccess) { XTLTRACE2_ERR(NdasVolTrace, 0, "DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS) failed.\n"); return NULL; } // returns the buffer return buffer.Detach(); }