Search code examples
c#.net-corentfsvhd

DiscUtils create an NTFS vhd


I am trying to create a virtual hard drive with NTFS in .NET Core.

I have found the DiscUtils NuGet package and the example code on their GitHub page works fine to create a VHD with FAT Format.

long diskSize = 30 * 1024 * 1024; //30MB
using (Stream vhdStream = File.Create(@"C:\TEMP\mydisk.vhd"))
{
    Disk disk = Disk.InitializeDynamic(vhdStream, diskSize);
    BiosPartitionTable.Initialize(disk, WellKnownPartitionType.WindowsFat);
    using (FatFileSystem fs = FatFileSystem.FormatPartition(disk, 0, null))
    {
        fs.CreateDirectory(@"TestDir\CHILD");
        // do other things with the file system...
    }
}

But for my use case I need files bigger than 2 GB. Because we're using Windows anyway, NTFS is okay. So I tried this code

long diskSize = 300 * 1024 * 1024; //300 MB
var vhdPath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "vhd"));

using (Stream vhdStream = File.Create(vhdPath))
{
    var disk = DiscUtils.Vhd.Disk.InitializeFixed(vhdStream, Ownership.None, diskSize);
    BiosPartitionTable.Initialize(disk, WellKnownPartitionType.WindowsNtfs);
    using (var ntfs = NtfsFileSystem.Format(vhdStream, "Virtual NTFS drive", Geometry.FromCapacity(diskSize), 0, diskSize / Sizes.Sector))
    {
        ntfs.CreateDirectory(@"TestDir\CHILD");

        // do other things with the file system...
    }
}

This code creates a 300 MB VHD that I can open with 7zip, but it contains a ~300 MB *.mbr file. If I try to open that it opens up a new 7zip window in the temp Folder. If I doubleclock that vhd, I get a Windows error "The drive Image is not initialized, contains unrecognized partitions or contains volumes that were not assigned to drive letters. Use the drive Management-Snap-In to assure that the drive, the partitions and the volumes are in a usable state." (freely translated from German)

After that I can't Access the file anymore because some Windows process is still keeping it busy.

What do I misunderstand here?

Is there an other way to create/mount VHDs with C# and .NET Core?


Solution

  • I got the answer from EricZimmerman on the projects GitHub page:

    var diskSize = 2000 * 1024 * 1024;
    var asVhd = false;
    
    using (var fs = new FileStream(_vhfxFileName, FileMode.OpenOrCreate))
    {
        VirtualDisk destDisk = Disk.InitializeDynamic(fs, Ownership.None, diskSize);
    
        if (asVhd)
        {
            destDisk = DiscUtils.Vhd.Disk.InitializeDynamic(fs, Ownership.None, diskSize);
        }
    
        BiosPartitionTable.Initialize(destDisk, WellKnownPartitionType.WindowsNtfs);
        var volMgr = new VolumeManager(destDisk);
    
        var label = $"ZZZZZZ ({dateStamp})";
    
        using (var destNtfs = NtfsFileSystem.Format(volMgr.GetLogicalVolumes()[0], label, new NtfsFormatOptions()))
        {
            destNtfs.NtfsOptions.ShortNameCreation = ShortFileNameOption.Disabled;
    
            var destDirectory = Path.GetDirectoryName(@"Some file");
            destNtfs.CreateDirectory(destDirectory, nfo);
    
            using (Stream source = new FileStream(@"Some file2", FileMode.Open, FileAccess.Read))
            {
                var destFileName = @"foo";
    
                using (Stream dest = destNtfs.OpenFile(destFileName, FileMode.Create, FileAccess.ReadWrite))
                {
                    source.CopyTo(dest);
                    dest.Flush();
                }
            }
            // do more stuff here
        }
    
        // commit everything to the stream before closing
        fs.Flush();
    }
    

    Works for me! Enjoy :)