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();
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
}
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();
}
Beispiel #5
0
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;
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
}
Beispiel #8
0
//
// 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();
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
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();
}