【问题标题】:Validate that a .vhd file is actually a vhd验证 .vhd 文件实际上是 vhd
【发布时间】:2019-01-21 17:42:06
【问题描述】:

用户可以将 vhd 文件上传到我的服务器。我想验证他们上传的文件,并确保它们实际上是有效的 vhd 文件,而不是使用 .vhd 文件扩展名等重新命名的 jpeg。有没有办法做到这一点?

【问题讨论】:

  • 我不太熟悉 .vhd 文件,但也许您可以在某种阅读器中打开它并验证文件的内部结构是否符合规范?微软在这里有规格:microsoft.com/en-us/download/details.aspx?id=23850免责声明:除了找到那个链接,我没有研究这个)
  • 图像中有一个 ascii 标头,您可以使用记事本查看或使用 BinaryReader 读取。
  • 所做的编辑:参见编辑 6。

标签: c# asp.net validation vhd


【解决方案1】:

https://www.garykessler.net/library/file_sigs.html(Ctrl + F,然后输入 VHD)

看来VHD文件的前8个字节如下:63 6F 6E 65 63 74 69 78conectix in ASCII.)

正如@jdweng 在 cmets 部分中所建议的,您也许可以使用BinaryReader 读取前 8 个字节,并将其与上面的值进行比较以确定文件是否为 VHD 文件。 s>

编辑:不起作用,正在寻找其他解决方案。

编辑2:实际上文件中似乎确实存在文本conectix,但它不在文件的开头;文本位于[the end of the file] - 0x200'th 字节。现在要去测试了。仅供参考,该文件是使用 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。 (需要 C# 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: According to the specs,似乎“硬盘页脚”位于最后 512(如果在 MS Virtual PC 2004 之前创建,则为 511)字节。

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 字节页脚的文件。另外,我添加了一些 cmets 来帮助维护。

/// <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
}

有一些条件编译位,但我相信您可以删除不必要的位以满足您的需要。

【讨论】:

  • 这似乎也对我有用。除非有人能想到更好的东西,否则我会使用它。
  • @Edgar Arakelyan 实际上我只是注意到任何小于 0.5KB 的文件都会导致问题。我不知道合法的 .vhd 文件是否可以小于 0.5KB,但如果不是这种情况,您可以添加一个逻辑检查文件大小是否小于 512 字节并返回 false。我会在几分钟内详细说明。
  • 我不相信您可以创建小于 1 mb 的 vhd。至少窗口的磁盘管理器工具也不会允许你。
  • 你可以随意改变它.
猜你喜欢
  • 2012-02-04
  • 1970-01-01
  • 2014-05-24
  • 2016-10-15
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多