Пользователи могут загружать файлы VHD на мой сервер. Я хотел бы проверить файлы, которые они загружают, и убедиться, что они действительно являются действительным файлом VHD, а не файлом jpeg, переименованным с расширением файла .vhd или т. Д. Есть ли способ сделать это?
Убедитесь, что файл .vhd на самом деле является VHD
Ответы (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
}
Есть некоторые условные биты компиляции, но я считаю, что вы можете удалить ненужные биты, чтобы соответствовать вашим потребностям.