Убедитесь, что файл .vhd на самом деле является VHD

Пользователи могут загружать файлы VHD на мой сервер. Я хотел бы проверить файлы, которые они загружают, и убедиться, что они действительно являются действительным файлом VHD, а не файлом jpeg, переименованным с расширением файла .vhd или т. Д. Есть ли способ сделать это?


person Edgar Arakelyan    schedule 21.01.2019    source источник
comment
Я не совсем знаком с файлами .vhd, но, возможно, вы могли бы просто открыть его в каком-нибудь ридере и убедиться, что внутренности файла соответствуют спецификациям? У Microsoft есть спецификации здесь: microsoft.com/en-us/ download/details.aspx?id=23850 (отказ от ответственности: я не изучал это, кроме как найти эту ссылку)   -  person Broots Waymb    schedule 21.01.2019
comment
В изображениях есть заголовок ascii, который можно просмотреть с помощью Блокнота или прочитать с помощью BinaryReader.   -  person jdweng    schedule 21.01.2019
comment
Внесенные правки: См. Правку 6.   -  person Gnbrkm41    schedule 22.01.2019


Ответы (1)


https://www.garykessler.net/library/file_sigs.html (Ctrl + F, затем введите VHD)

Похоже, что первые 8 байт файлов VHD выглядят следующим образом: 63 6F 6E 65 63 74 69 78 (conectix в ASCII.)

Как предложил @jdweng в разделе комментариев, вы можете использовать BinaryReader, чтобы прочитать первые 8 байтов и сравнить их со значением над ним, чтобы определить, является ли файл файлом VHD.

Изменить: не работает, ищите другие решения.

Редактировать 2: на самом деле кажется, что текст conectix действительно существует в файле, однако он не находится в начале файла; текст расположен в [the end of the file] - 0x200'м байте. Сейчас собираюсь протестировать. К вашему сведению, файл создается с помощью инструмента управления дисками в Windows 10.

Редактировать 3:

private static bool IsVhd(string path)
{
    byte[] vhdHeader = { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
    byte[] header;

    FileInfo file = new FileInfo(path);
    long length = file.Length;

    using (BinaryReader br = new BinaryReader(file.OpenRead()))
    {
        br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
        header = br.ReadBytes(8);
    }

    return vhdHeader.SequenceEqual(header);
}

Я считаю, что это будет делать.

Редактировать 4:

private static bool IsVhd(string path)
{
    Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
    Span<byte> header = stackalloc byte[8];

    FileInfo file = new FileInfo(path);
    long length = file.Length;

    using (BinaryReader br = new BinaryReader(file.OpenRead()))
    {
        br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
        br.Read(header);
    }

    return vhdHeader.SequenceEqual(header);
}

Неверсия с меньшим объемом памяти, если вы используете .NET Core. (Требуется С# 7.3)

Редактировать 5:

private static bool IsVhd(string path)
{
    Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
    Span<byte> header = stackalloc byte[8];

    FileInfo file = new FileInfo(path);
    long length = file.Length;

    using (BinaryReader br = new BinaryReader(file.OpenRead()))
    {
        br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
        for (int i = 0; i < 8; i++)
            header[i] = br.ReadByte();
    }

    return vhdHeader.SequenceEqual(header);
}

То же самое, но для .NET Frameworks (в идеале версия 4.7.1 из-за оптимизации; также требуется пакет System.Memory NuGet. C# 7.3)

Изменить 6: согласно спецификациям кажется что «нижний колонтитул жесткого диска» расположен на последних 512 (511, если он создан до MS Virtual PC 2004) байтах.

Note: Versions previous to Microsoft Virtual PC 2004 create disk images that have a 511-byte disk footer. So the hard disk footer can exist in the last 511 or 512 bytes of the file that holds the hard disk image.

Hard Disk Footer Field Descriptions
The following provides detailed definitions of the hard disk footer fields.
Cookie
Cookies are used to uniquely identify the original creator of the hard disk image. The values are case-sensitive.
Microsoft uses the “conectix” string to identify this file as a hard disk image created by Microsoft Virtual Server, Virtual PC, and predecessor products. The cookie is stored as an eight-character ASCII string with the “c” in the first byte, the “o” in the second byte, and so on.

Предыдущие коды, которые я написал, не будут работать, если размер файла меньше 512 байт. Я исправил это, так что теперь он будет работать и с файлами с нижним колонтитулом 511 байт. Кроме того, я добавил несколько комментариев, чтобы помочь поддерживать.

/// <summary>
/// Determines whether the file indicated by the given path is a valid Virtual Hard Disk (.vhd) file.
/// </summary>
/// <param name="path">The path to the .vhd file to check.</param>
/// <returns>Whether the file is a valid vhd file or not.</returns>
//https://www.microsoft.com/en-us/download/details.aspx?id=23850
//See 'Hard Disk Footer Format'
//ASCII string "conectix" (63 6F 6E 65 63 74 69 78) is stored at the last 512 (511 if created on legacy platforms) bytes of the file
private static bool IsVhd(string path)
{
    if (path is null) throw new ArgumentNullException(nameof(path));

    Span<byte> vhdFooterCookie = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
    Span<byte> cookie = stackalloc byte[9];

    FileInfo file = new FileInfo(path);
    long length = file.Length;
    if (length < 511) return false; //Cannot be smaller than 512 bytes

    using (BinaryReader br = new BinaryReader(file.OpenRead()))
    {
        br.BaseStream.Position = length - 0x200; //Where the footer starts from
#if NETCOREAPP
        br.Read(cookie);
#else
        for (int i = 0; i < 9; i++)
            cookie[i] = br.ReadByte();
#endif
    }

    //SequenceEqual returns false if length is not equal, therefore we slice it to match
    return vhdFooterCookie.SequenceEqual(cookie.Slice(0, 8)) 
           || vhdFooterCookie.SequenceEqual(cookie.Slice(1)); //If created on legacy platform
}

Есть некоторые условные биты компиляции, но я считаю, что вы можете удалить ненужные биты, чтобы соответствовать вашим потребностям.

person Gnbrkm41    schedule 21.01.2019
comment
Кажется, это работает и для меня. Я буду использовать это, если кто-то не может придумать что-то лучше. - person Edgar Arakelyan; 22.01.2019
comment
@Edgar Arakelyan На самом деле я только что заметил, что любые файлы размером менее 0,5 КБ могут вызвать проблемы. Я не знаю, могут ли законные файлы .vhd быть меньше 0,5 КБ, но если это не так, вы можете добавить логическую проверку, если размер файла меньше 512 байт, и вернуть false. Я подробно расскажу об этом через несколько минут. - person Gnbrkm41; 22.01.2019
comment
Я не верю, что вы можете создать виртуальный жесткий диск размером менее 1 МБ. По крайней мере, инструмент управления дисками окна не позволит вам. - person Edgar Arakelyan; 22.01.2019
comment
Вы можете изменить это :) Я думал, что должен изменить и это, но я не мог подтвердить, верно ли это для всех файлов VHD или только для файлов, созданных в последних ОС Windows. - person Gnbrkm41; 22.01.2019