void VirtualizationInstance::FindBytesPerSectorAndAlignment()

in ProjectedFSLib.Managed.API/VirtualizationInstance.cpp [1217:1306]


void VirtualizationInstance::FindBytesPerSectorAndAlignment()
{
    WCHAR volumePath[MAX_PATH];
    pin_ptr<const WCHAR> rootPath = PtrToStringChars(m_virtualizationRootPath);
    if (!GetVolumePathName(rootPath,
                           volumePath,
                           ARRAYSIZE(volumePath)))
    {
        DWORD lastError = ::GetLastError();
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to get volume path name, Error: {0}",
                                               lastError));
    }

    WCHAR volumeName[VOLUME_PATH_LENGTH + 1];
    if (!GetVolumeNameForVolumeMountPoint(volumePath,
                                          volumeName,
                                          ARRAYSIZE(volumeName)))
    {
        DWORD lastError = ::GetLastError();
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to get volume name for volume mount point: {0}, Error: {1}",
                                               gcnew String(volumeName),
                                               lastError));
    }

    if (wcslen(volumeName) != VOLUME_PATH_LENGTH || volumeName[VOLUME_PATH_LENGTH - 1] != L'\\')
    {
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Volume name {0} is not in expected format",
                                               gcnew String(volumeName)));
    }

    HANDLE rootHandle = CreateFile(volumeName,
                                   0,
                                   0,
                                   NULL,
                                   OPEN_EXISTING,
                                   FILE_FLAG_BACKUP_SEMANTICS,
                                   NULL);
    if (rootHandle == INVALID_HANDLE_VALUE)
    {
        DWORD lastError = ::GetLastError();
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to get handle to {0}, Error: {1}", m_virtualizationRootPath,
                                               lastError));
    }

    FILE_STORAGE_INFO storageInfo = {};
    if (!GetFileInformationByHandleEx(rootHandle,
                                      FileStorageInfo,
                                      &storageInfo,
                                      sizeof(storageInfo)))
    {
        DWORD lastError = ::GetLastError();
        CloseHandle(rootHandle);
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to query sector size of volume, Error: {0}",
                                               lastError));
    }

    FILE_ALIGNMENT_INFO alignmentInfo = {};
    if (!GetFileInformationByHandleEx(rootHandle,
                                      FileAlignmentInfo,
                                      &alignmentInfo,
                                      sizeof(alignmentInfo)))
    {
        DWORD lastError = ::GetLastError();
        CloseHandle(rootHandle);
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to query device alignment, Error: {0}",
                                               lastError));
    }

    m_bytesPerSector = storageInfo.LogicalBytesPerSector;

    // AlignmentRequirement returns the required alignment minus 1 
    // https://msdn.microsoft.com/en-us/library/cc232065.aspx
    // https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/initializing-a-device-object
    m_writeBufferAlignmentRequirement = alignmentInfo.AlignmentRequirement + 1;

    CloseHandle(rootHandle);

    if (!IsPowerOf2(m_writeBufferAlignmentRequirement))
    {
        throw gcnew IOException(String::Format(CultureInfo::InvariantCulture,
                                               "Failed to determine write buffer alignment requirement: {0} is not a power of 2",
                                               m_writeBufferAlignmentRequirement));
    }
}