Browse Source

commit: Upgrade Framework; Block Differencing Disk Image; Update GUI

HOME 4 years ago
parent
commit
a9bfca6e73

+ 18 - 1
DiskAccessLibrary/DiskAccessLibrary.csproj

@@ -1,4 +1,4 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -14,6 +14,8 @@
     <UpgradeBackupLocation>
     </UpgradeBackupLocation>
     <OldToolsVersion>2.0</OldToolsVersion>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <TargetFrameworkProfile />
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -23,6 +25,8 @@
     <DefineConstants>DEBUG;TRACE;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <LangVersion>8</LangVersion>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -31,6 +35,8 @@
     <DefineConstants>TRACE;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <LangVersion>8</LangVersion>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
@@ -194,6 +200,15 @@
     <Compile Include="LogicalDiskManager\Volumes\SimpleVolume.cs" />
     <Compile Include="LogicalDiskManager\Volumes\SpannedVolume.cs" />
     <Compile Include="LogicalDiskManager\Volumes\StripedVolume.cs" />
+    <Compile Include="Mod\BlockDifferencingDiskImage\BddInfo.cs" />
+    <Compile Include="Mod\BlockDifferencingDiskImage\BlockDifferencingDiskImage.cs" />
+    <Compile Include="Mod\BlockDifferencingDiskImage\BlockEntryAllocateFlagIndexer.cs" />
+    <Compile Include="Mod\BlockDifferencingDiskImage\BlockEntryOffsetIndexer.cs" />
+    <Compile Include="Mod\Consts.cs" />
+    <Compile Include="Mod\DiskImage.cs" />
+    <Compile Include="Mod\DiskImageCreator.cs" />
+    <Compile Include="Mod\DiskImageFormat.cs" />
+    <Compile Include="Mod\DiskImageType.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionEntry.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionEntryCollection.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionTable.cs" />
@@ -235,6 +250,7 @@
     <Compile Include="Win32\Volumes\VolumeHandlePool.cs" />
   </ItemGroup>
   <ItemGroup>
+    <Content Include="Mod\BlockDifferencingDiskImage\BddFormat.txt" />
     <Content Include="RevisionHistory.txt" />
   </ItemGroup>
   <ItemGroup>
@@ -243,6 +259,7 @@
       <Name>Utilities</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 12 - 8
DiskAccessLibrary/Disks/DiskImage.cs

@@ -1,13 +1,11 @@
 /* Copyright (C) 2014-2018 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
- * 
+ *
  * You can redistribute this program and/or modify it under the terms of
  * the GNU Lesser Public License as published by the Free Software Foundation,
  * either version 3 of the License, or (at your option) any later version.
  */
+
 using System;
-using System.Collections.Generic;
-using System.IO;
-using Utilities;
 
 namespace DiskAccessLibrary
 {
@@ -39,7 +37,9 @@ namespace DiskAccessLibrary
         public abstract bool ExclusiveLock();
 
 #if Win32
+
         public abstract bool ExclusiveLock(bool useOverlappedIO);
+
 #endif
 
         public abstract bool ReleaseLock();
@@ -79,14 +79,18 @@ namespace DiskAccessLibrary
             {
                 return new VirtualHardDisk(path, isReadOnly);
             }
-            else if (path.EndsWith(".vmdk", StringComparison.InvariantCultureIgnoreCase))
+
+            if (path.EndsWith(".vmdk", StringComparison.InvariantCultureIgnoreCase))
             {
                 return new VirtualMachineDisk(path, isReadOnly);
             }
-            else
+
+            if (path.EndsWith(".bdd", StringComparison.InvariantCultureIgnoreCase))
             {
-                return new RawDiskImage(path, isReadOnly);
+                return new BlockDifferencingDiskImage(path, isReadOnly);
             }
+
+            return new RawDiskImage(path, isReadOnly);
         }
     }
-}
+}

+ 32 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BddFormat.txt

@@ -0,0 +1,32 @@
+Sln - 1
+=======
+2: Length of based image file path
+N: Based image file path UTF-8
+4: Size of Block Byte
+4: Number of Blocks | BlockSize * NumberOfBlocks Must equal to Based image
+N: Block index table
+N: Dynamic allocated data blocks
+
+Sln - 2
+=======
+65535-8: Fixed Based image file path UTF-8
+4: Size of Block Byte
+4: Number of Blocks | BlockSize * NumberOfBlocks Must equal to Based image
+N: Block index table
+N: Dynamic allocated data blocks
+
+
+Block index entry
+=================
+4: Flags
+    Bit0: when allocated then set bit0 from 0 to 1
+    Bit1-31: Resvered
+8: Offset 64bit unsigned integer
+4: Resvered, Checksum?
+
+
+Block index entry Rev.2
+=======================
+8: Compound bits
+    Bit0~62: Offset of data block
+    Bit63: Allocated flag

+ 71 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BddInfo.cs

@@ -0,0 +1,71 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace DiskAccessLibrary
+{
+    public class BddInfo
+    {
+        public const int BlockIndexEntrySize = 8;
+
+        public string BasedImagePath { get; }
+
+        public long Length { get; }
+
+        public int BlockSize { get; }
+        public int NumberOfBlocks { get; }
+
+        public long DataOffset { get; }
+
+        public long EntryTableOffset { get; }
+
+        public BlockEntryAllocateFlagIndexer Allocated { get; }
+
+        public BlockEntryOffsetIndexer Offset { get; set; }
+
+        public IReadOnlyList<ulong> Entries { get; }
+
+        public BddInfo(string snapshotImagePath, bool readEntries = true)
+        {
+            using var fs = new FileStream(snapshotImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+            using var reader = new BinaryReader(fs);
+
+            int basedPathLength = reader.ReadUInt16(); //2
+            BasedImagePath = Encoding.UTF8.GetString(reader.ReadBytes(basedPathLength)); //N
+            BlockSize = reader.ReadInt32(); //4
+            NumberOfBlocks = reader.ReadInt32(); //4
+
+            var snapMatchLength = NumberOfBlocks * (long)BlockSize;
+            Length = snapMatchLength;
+
+            if (false == readEntries) return;
+
+            var baseInfo = new FileInfo(BasedImagePath);
+            if (snapMatchLength != baseInfo.Length)
+                throw new InvalidDataException("Snapshot size no match to based image");
+
+            EntryTableOffset = fs.Position;
+
+            var arr = new ulong[NumberOfBlocks];
+            for (var i = 0; i < NumberOfBlocks; i++)
+            {
+                arr[i] = reader.ReadUInt64();
+            }
+
+            Entries = arr;
+            DataOffset = fs.Position;
+
+            Allocated = new BlockEntryAllocateFlagIndexer(arr);
+            Offset = new BlockEntryOffsetIndexer(arr);
+        }
+
+
+        public static int CalcHeaderSize(string basedImagePath, int blockSize, out int blocks)
+        {
+            var baseLength = new FileInfo(basedImagePath).Length;
+            blocks = (int)(baseLength / blockSize);
+
+            return 2 + Encoding.UTF8.GetByteCount(basedImagePath) + 8 + blocks * BlockIndexEntrySize;
+        }
+    }
+}

+ 245 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BlockDifferencingDiskImage.cs

@@ -0,0 +1,245 @@
+using System;
+using System.IO;
+using System.Security.Authentication;
+using System.Text;
+
+namespace DiskAccessLibrary
+{
+    public class BlockDifferencingDiskImage : DiskImage
+    {
+        private const int SectorSize = 512;
+
+        private BddInfo BddInfo { get; }
+
+        private bool _isExclusiveLock;
+
+        private FileStream _basedFileStream;
+        private FileStream _snapshotFileStream;
+
+        public BlockDifferencingDiskImage(string diskImagePath, bool isReadOnly) : base(diskImagePath, isReadOnly)
+        {
+            BddInfo = new BddInfo(diskImagePath);
+
+            if (isReadOnly)
+            {
+                _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
+                _snapshotFileStream = File.OpenRead(Path);
+            }
+            else
+            {
+                _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
+                _snapshotFileStream = File.Open(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
+                _isExclusiveLock = true;
+            }
+        }
+
+        private void ReadBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset)
+        {
+            if (false == BddInfo.Allocated[blockIndex])
+            {
+                _basedFileStream.Position = (long)blockIndex * BddInfo.BlockSize + blockOffset;
+
+                while (count > 0)
+                {
+                    var read = _basedFileStream.Read(buffer, offset, count);
+                    offset += read;
+                    count -= read;
+                }
+            }
+            else
+            {
+                _snapshotFileStream.Position = BddInfo.Offset[blockIndex] + blockOffset;
+                while (count > 0)
+                {
+                    var read = _snapshotFileStream.Read(buffer, offset, count);
+                    offset += read;
+                    count -= read;
+                }
+            }
+        }
+
+        private void WriteBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset)
+        {
+            if (false == BddInfo.Allocated[blockIndex])
+            {
+                //COW:allocate block
+
+                _snapshotFileStream.Position = _snapshotFileStream.Length;
+                BddInfo.Offset[blockIndex] = _snapshotFileStream.Position;
+
+                //copy leading block from based image
+                if (blockOffset > 0)
+                {
+                    var readCount = blockOffset;
+                    var bufLeading = new byte[readCount];
+                    _basedFileStream.Position = (long)blockIndex * BddInfo.BlockSize;
+
+                    var readOffset = 0;
+                    while (readCount > 0)
+                    {
+                        var read = _basedFileStream.Read(bufLeading, readOffset, readCount);
+                        readOffset += read;
+                        readCount -= read;
+                    }
+
+                    _snapshotFileStream.Position = BddInfo.Offset[blockIndex];
+                    _snapshotFileStream.Write(bufLeading, 0, bufLeading.Length);
+                }
+
+                //write to snapshot directly
+                _snapshotFileStream.Position = BddInfo.Offset[blockIndex] + blockOffset;
+                _snapshotFileStream.Write(buffer, offset, count);
+
+                //copy suffix block from based image
+                if (blockOffset + count < BddInfo.BlockSize)
+                {
+                    var suffixOffset = blockOffset + count;
+                    var readCount = BddInfo.BlockSize - suffixOffset;
+                    var bufSuffix = new byte[readCount];
+                    _basedFileStream.Position = (long)blockIndex * BddInfo.BlockSize + suffixOffset;
+
+                    var readOffset = 0;
+                    while (readCount > 0)
+                    {
+                        var read = _basedFileStream.Read(bufSuffix, readOffset, readCount);
+                        readOffset += read;
+                        readCount -= read;
+                    }
+
+                    _snapshotFileStream.Position = BddInfo.Offset[blockIndex] + suffixOffset;
+                    _snapshotFileStream.Write(bufSuffix, 0, bufSuffix.Length);
+                }
+
+                BddInfo.Allocated[blockIndex] = true;
+                _snapshotFileStream.Position = BddInfo.EntryTableOffset + BddInfo.BlockIndexEntrySize * blockIndex;
+                var bufEntry = BitConverter.GetBytes(BddInfo.Entries[blockIndex]);
+                _snapshotFileStream.Write(bufEntry, 0, bufEntry.Length);
+            }
+            else
+            {
+                _snapshotFileStream.Position = BddInfo.Offset[blockIndex] + blockOffset;
+                _snapshotFileStream.Write(buffer, offset, count);
+            }
+        }
+
+        public override byte[] ReadSectors(long sectorIndex, int sectorCount)
+        {
+            var rawOffset = sectorIndex * SectorSize;
+            var rawSize = sectorCount * SectorSize;
+
+            var buffer = new byte[rawSize];
+
+            for (var i = 0; i < rawSize;)
+            {
+                var blockIndex = (int)(rawOffset / BddInfo.BlockSize);
+                var blockOffset = (int)(rawOffset % BddInfo.BlockSize);
+                var bytesToRead = BddInfo.BlockSize - blockOffset;
+
+                if (i + bytesToRead > rawSize)
+                {
+                    bytesToRead = rawSize - i;
+                }
+
+                ReadBlock(buffer, i, bytesToRead, blockIndex, blockOffset);
+
+                i += bytesToRead;
+                rawOffset += bytesToRead;
+            }
+
+            return buffer;
+        }
+
+        public override void WriteSectors(long sectorIndex, byte[] data)
+        {
+            if (IsReadOnly) throw new AuthenticationException("Read only");
+
+            var rawOffset = sectorIndex * SectorSize;
+
+            for (var i = 0; i < data.Length;)
+            {
+                var blockIndex = (int)(rawOffset / BddInfo.BlockSize);
+                var blockOffset = (int)(rawOffset % BddInfo.BlockSize);
+                var bytesToWrite = BddInfo.BlockSize - blockOffset;
+
+                if (i + bytesToWrite > data.Length)
+                {
+                    bytesToWrite = data.Length - i;
+                }
+
+                WriteBlock(data, i, bytesToWrite, blockIndex, blockOffset);
+
+                i += bytesToWrite;
+                rawOffset += bytesToWrite;
+            }
+        }
+
+        public override bool ExclusiveLock()
+        {
+            if (_isExclusiveLock) return true;
+
+            _basedFileStream?.Close();
+            _snapshotFileStream?.Close();
+
+            _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
+            _snapshotFileStream = File.Open(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
+
+            _isExclusiveLock = true;
+
+            return true;
+        }
+
+        public override bool ReleaseLock()
+        {
+            _basedFileStream?.Close();
+            _snapshotFileStream?.Close();
+            _isExclusiveLock = false;
+            return true;
+        }
+
+        public static BlockDifferencingDiskImage Create(string based, string snapshot, int blockSize)
+        {
+            var fileInfo = new FileInfo(based);
+
+            if (fileInfo.Length % blockSize != 0) throw new ArgumentException("Block size no mul to base image size", nameof(blockSize));
+
+            using var stream = File.Create(snapshot);
+            using var writer = new BinaryWriter(stream);
+
+            //create bdd struct
+
+            var bufBasedPath = Encoding.UTF8.GetBytes(System.IO.Path.GetFullPath(based));
+            var numberOfBlocks = (int)(fileInfo.Length / blockSize);
+            writer.Write((ushort)bufBasedPath.Length);
+            writer.Write(bufBasedPath);
+            writer.Write(blockSize);
+            writer.Write(numberOfBlocks);
+            writer.Flush();
+            stream.SetLength(stream.Length + numberOfBlocks * BddInfo.BlockIndexEntrySize);
+            writer.Close();
+            stream.Close();
+
+            //return instance
+            return new BlockDifferencingDiskImage(snapshot);
+        }
+
+        public override long Size => BddInfo.Length;
+
+        public override int BytesPerSector => SectorSize;
+
+        ////////////////////////////////////////////////////////////////////////////////////
+
+        public BlockDifferencingDiskImage(string diskImagePath) : this(diskImagePath, false)
+        {
+        }
+
+        public override bool ExclusiveLock(bool useOverlappedIO)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override void Extend(long numberOfAdditionalBytes)
+        {
+            throw new System.NotImplementedException();
+        }
+    }
+}

+ 25 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BlockEntryAllocateFlagIndexer.cs

@@ -0,0 +1,25 @@
+namespace DiskAccessLibrary
+{
+    public class BlockEntryAllocateFlagIndexer
+    {
+        private const ulong FlagAllocated = 1UL << 63;
+
+        private readonly ulong[] _entries;
+
+        public BlockEntryAllocateFlagIndexer(ulong[] entries)
+        {
+            _entries = entries;
+        }
+
+        public bool this[int index]
+        {
+            get => 0 != (_entries[index] & FlagAllocated);
+
+            set
+            {
+                if (value) _entries[index] |= FlagAllocated;
+                else _entries[index] &= ~FlagAllocated;
+            }
+        }
+    }
+}

+ 20 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BlockEntryOffsetIndexer.cs

@@ -0,0 +1,20 @@
+namespace DiskAccessLibrary
+{
+    public class BlockEntryOffsetIndexer
+    {
+        private const ulong MaskOffset = (1UL << 63) - 1;
+        private const ulong MaskClear = ~MaskOffset;
+        private readonly ulong[] _entries;
+
+        public BlockEntryOffsetIndexer(ulong[] entries)
+        {
+            _entries = entries;
+        }
+
+        public long this[int index]
+        {
+            get => (long)(_entries[index] & MaskOffset);
+            set => _entries[index] = (_entries[index] & MaskClear) | ((ulong)value & MaskOffset);
+        }
+    }
+}

+ 15 - 0
DiskAccessLibrary/Mod/Consts.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DiskAccessLibrary.Mod
+{
+    public static class Consts
+    {
+        public const int KiloByte = 1024;
+        public const int MegaByte = 1024 * KiloByte;
+
+    }
+}

+ 56 - 0
DiskAccessLibrary/Mod/DiskImage.cs

@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+using System.Text;
+using static DiskAccessLibrary.Mod.Consts;
+
+namespace DiskAccessLibrary
+{
+    public abstract partial class DiskImage
+    {
+        public static string GetDiskImageInfo(string path)
+        {
+            if (path == null) throw new ArgumentNullException(nameof(path));
+
+            var info = new StringBuilder();
+            if (false == File.Exists(path))
+            {
+                info.AppendLine("** File not found **");
+            }
+            else
+            {
+                var extension = System.IO.Path.GetExtension(path).ToLower();
+                switch (extension)
+                {
+                    default:
+                        info.AppendLine($"No info for extension {extension}");
+                        break;
+
+                    case ".bdd":
+                        info.AppendLine("Block Differencing Disk Image");
+                        var bdd = new BddInfo(path, false);
+
+                        if (false == File.Exists(bdd.BasedImagePath))
+                        {
+                            info.AppendLine("** Based image file not found **");
+                            info.AppendLine($"Based on: {bdd.BasedImagePath}");
+                            break;
+                        }
+
+                        var baseLength = new FileInfo(bdd.BasedImagePath).Length;
+
+                        info.AppendLine($"Based on:    {bdd.BasedImagePath}");
+                        info.AppendLine($"Based Size:  {baseLength / MegaByte:N0} MB");
+                        info.AppendLine($"Block Size:  {bdd.BlockSize / KiloByte:N0} KB");
+                        info.AppendLine($"Block Count: {bdd.NumberOfBlocks:N0}");
+                        info.AppendLine($"Fully Size:  {bdd.Length / MegaByte:N0} MB");
+
+                        if (baseLength != bdd.Length) info.AppendLine("** Fully Size not match to base **");
+
+                        break;
+                }
+            }
+
+            return info.ToString();
+        }
+    }
+}

+ 45 - 0
DiskAccessLibrary/Mod/DiskImageCreator.cs

@@ -0,0 +1,45 @@
+using System;
+
+namespace DiskAccessLibrary
+{
+    public static class DiskImageCreator
+    {
+        public static DiskImage CreateImage(DiskImageFormat format, DiskImageType type, string imagePath, long imageSize, string snapshotPath, int blockSize)
+        {
+            switch (format)
+            {
+                case DiskImageFormat.BlockDifferencingDiskImage:
+
+                    if (type != DiskImageType.Differencing) throw new NotSupportedException();
+
+                    return BlockDifferencingDiskImage.Create(imagePath, snapshotPath, blockSize);
+
+                case DiskImageFormat.RawDiskImage:
+
+                    if (type != DiskImageType.Fixed) throw new NotSupportedException();
+
+                    return RawDiskImage.Create(imagePath, imageSize);
+
+                case DiskImageFormat.VirtualHardDisk:
+
+                    switch (type)
+                    {
+                        case DiskImageType.Differencing:
+                            throw new NotSupportedException();
+
+                        case DiskImageType.Dynamic:
+                            return VirtualHardDisk.CreateDynamicDisk(imagePath, imageSize);
+
+                        case DiskImageType.Fixed:
+                            return VirtualHardDisk.CreateFixedDisk(imagePath, imageSize);
+
+                        default:
+                            throw new ArgumentOutOfRangeException(nameof(type), type, null);
+                    }
+
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(format), format, null);
+            }
+        }
+    }
+}

+ 9 - 0
DiskAccessLibrary/Mod/DiskImageFormat.cs

@@ -0,0 +1,9 @@
+namespace DiskAccessLibrary
+{
+    public enum DiskImageFormat
+    {
+        BlockDifferencingDiskImage,
+        RawDiskImage,
+        VirtualHardDisk,
+    }
+}

+ 9 - 0
DiskAccessLibrary/Mod/DiskImageType.cs

@@ -0,0 +1,9 @@
+namespace DiskAccessLibrary
+{
+    public enum DiskImageType
+    {
+        Differencing,
+        Dynamic,
+        Fixed,
+    }
+}

+ 5 - 1
ISCSI/ISCSI.csproj

@@ -1,4 +1,4 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -14,6 +14,8 @@
     <UpgradeBackupLocation>
     </UpgradeBackupLocation>
     <OldToolsVersion>2.0</OldToolsVersion>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <TargetFrameworkProfile />
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -23,6 +25,7 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -32,6 +35,7 @@
     </DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />

+ 1 - 1
ISCSI/SCSITarget/VirtualSCSITarget.cs

@@ -136,7 +136,7 @@ namespace SCSI
                     StandardInquiryData inquiryData = new StandardInquiryData();
                     inquiryData.PeripheralDeviceType = 0; // Direct access block device
                     inquiryData.VendorIdentification = "TalAloni";
-                    inquiryData.ProductIdentification = "SCSI Disk " + ((ushort)lun).ToString();
+                    inquiryData.ProductIdentification = "iSCSI Disk " + lun.ToString();
                     inquiryData.ProductRevisionLevel = "1.00";
                     inquiryData.DriveSerialNumber = 0;
                     inquiryData.CmdQue = true;

+ 10 - 9
ISCSIConsole/AddTargetForm.Designer.cs

@@ -37,8 +37,8 @@ namespace ISCSIConsole
             this.btnOK = new System.Windows.Forms.Button();
             this.btnCancel = new System.Windows.Forms.Button();
             this.listDisks = new System.Windows.Forms.ListView();
-            this.columnDescription = new System.Windows.Forms.ColumnHeader();
-            this.columnSize = new System.Windows.Forms.ColumnHeader();
+            this.columnDescription = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+            this.columnSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
             this.btnAddVolume = new System.Windows.Forms.Button();
             this.btnCreateDiskImage = new System.Windows.Forms.Button();
             this.btnRemove = new System.Windows.Forms.Button();
@@ -69,7 +69,7 @@ namespace ISCSIConsole
             // 
             this.txtTargetIQN.Location = new System.Drawing.Point(57, 12);
             this.txtTargetIQN.Name = "txtTargetIQN";
-            this.txtTargetIQN.Size = new System.Drawing.Size(275, 20);
+            this.txtTargetIQN.Size = new System.Drawing.Size(275, 21);
             this.txtTargetIQN.TabIndex = 1;
             // 
             // label1
@@ -77,7 +77,7 @@ namespace ISCSIConsole
             this.label1.AutoSize = true;
             this.label1.Location = new System.Drawing.Point(12, 15);
             this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(29, 13);
+            this.label1.Size = new System.Drawing.Size(29, 12);
             this.label1.TabIndex = 4;
             this.label1.Text = "IQN:";
             // 
@@ -86,7 +86,7 @@ namespace ISCSIConsole
             this.label2.AutoSize = true;
             this.label2.Location = new System.Drawing.Point(12, 51);
             this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(36, 13);
+            this.label2.Size = new System.Drawing.Size(41, 12);
             this.label2.TabIndex = 6;
             this.label2.Text = "Disks:";
             // 
@@ -124,8 +124,8 @@ namespace ISCSIConsole
             this.listDisks.TabIndex = 2;
             this.listDisks.UseCompatibleStateImageBehavior = false;
             this.listDisks.View = System.Windows.Forms.View.Details;
-            this.listDisks.SelectedIndexChanged += new System.EventHandler(this.listDisks_SelectedIndexChanged);
             this.listDisks.ColumnWidthChanging += new System.Windows.Forms.ColumnWidthChangingEventHandler(this.listDisks_ColumnWidthChanging);
+            this.listDisks.SelectedIndexChanged += new System.EventHandler(this.listDisks_SelectedIndexChanged);
             // 
             // columnDescription
             // 
@@ -173,7 +173,7 @@ namespace ISCSIConsole
             this.AcceptButton = this.btnOK;
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
             this.CancelButton = this.btnCancel;
-            this.ClientSize = new System.Drawing.Size(494, 235);
+            this.ClientSize = new System.Drawing.Size(484, 221);
             this.Controls.Add(this.btnRemove);
             this.Controls.Add(this.btnCreateDiskImage);
             this.Controls.Add(this.btnAddVolume);
@@ -192,13 +192,14 @@ namespace ISCSIConsole
             this.MaximumSize = new System.Drawing.Size(500, 260);
             this.MinimumSize = new System.Drawing.Size(500, 260);
             this.Name = "AddTargetForm";
+            this.ShowInTaskbar = false;
             this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
             this.Text = "Add iSCSI Target";
             this.Deactivate += new System.EventHandler(this.AddTargetForm_Deactivate);
-            this.Load += new System.EventHandler(this.AddTargetForm_Load);
-            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.AddTargetForm_KeyUp);
             this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AddTargetForm_FormClosing);
+            this.Load += new System.EventHandler(this.AddTargetForm_Load);
             this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AddTargetForm_KeyDown);
+            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.AddTargetForm_KeyUp);
             this.ResumeLayout(false);
             this.PerformLayout();
 

+ 3 - 3
ISCSIConsole/AddTargetForm.resx

@@ -112,12 +112,12 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         AAABAAYAAAAAAAEAIAAoIAQAZgAAAICAAAABACAAKAgBAI4gBABAQAAAAQAgAChCAAC2KAUAMDAAAAEA

+ 196 - 62
ISCSIConsole/CreateDiskImageForm.Designer.cs

@@ -29,42 +29,47 @@ namespace ISCSIConsole
         private void InitializeComponent()
         {
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateDiskImageForm));
-            this.saveVirtualDiskFileDialog = new System.Windows.Forms.SaveFileDialog();
-            this.numericDiskSize = new System.Windows.Forms.NumericUpDown();
+            this.ImageSizeUpDown = new System.Windows.Forms.NumericUpDown();
             this.lblSize = new System.Windows.Forms.Label();
-            this.label1 = new System.Windows.Forms.Label();
+            this.MbLabel = new System.Windows.Forms.Label();
             this.lblFilePath = new System.Windows.Forms.Label();
-            this.txtFilePath = new System.Windows.Forms.TextBox();
-            this.btnBrowse = new System.Windows.Forms.Button();
+            this.ImageFileTextBox = new System.Windows.Forms.TextBox();
+            this.ImageFileButton = new System.Windows.Forms.Button();
             this.btnOK = new System.Windows.Forms.Button();
             this.btnCancel = new System.Windows.Forms.Button();
-            ((System.ComponentModel.ISupportInitialize)(this.numericDiskSize)).BeginInit();
+            this.FormatLabel = new System.Windows.Forms.Label();
+            this.FormatComboBox = new System.Windows.Forms.ComboBox();
+            this.TypeLabel = new System.Windows.Forms.Label();
+            this.TypeComboBox = new System.Windows.Forms.ComboBox();
+            this.SnapshotLabel = new System.Windows.Forms.Label();
+            this.SnapshotTextBox = new System.Windows.Forms.TextBox();
+            this.SnapshotButton = new System.Windows.Forms.Button();
+            this.BlockSizeLabel = new System.Windows.Forms.Label();
+            this.KbLabel = new System.Windows.Forms.Label();
+            this.AheadLabel = new System.Windows.Forms.Label();
+            this.BlockSizeUpDown = new System.Windows.Forms.DomainUpDown();
+            ((System.ComponentModel.ISupportInitialize)(this.ImageSizeUpDown)).BeginInit();
             this.SuspendLayout();
             // 
-            // saveVirtualDiskFileDialog
+            // ImageSizeUpDown
             // 
-            this.saveVirtualDiskFileDialog.FileName = "Disk.vhd";
-            this.saveVirtualDiskFileDialog.Filter = "Virtual Hard Disk (*.vhd)|*.vhd";
-            // 
-            // numericDiskSize
-            // 
-            this.numericDiskSize.Location = new System.Drawing.Point(56, 41);
-            this.numericDiskSize.Maximum = new decimal(new int[] {
+            this.ImageSizeUpDown.Location = new System.Drawing.Point(106, 64);
+            this.ImageSizeUpDown.Maximum = new decimal(new int[] {
             16777215,
             0,
             0,
             0});
-            this.numericDiskSize.Minimum = new decimal(new int[] {
+            this.ImageSizeUpDown.Minimum = new decimal(new int[] {
             1,
             0,
             0,
             0});
-            this.numericDiskSize.Name = "numericDiskSize";
-            this.numericDiskSize.Size = new System.Drawing.Size(86, 20);
-            this.numericDiskSize.TabIndex = 0;
-            this.numericDiskSize.ThousandsSeparator = true;
-            this.numericDiskSize.Value = new decimal(new int[] {
-            100,
+            this.ImageSizeUpDown.Name = "ImageSizeUpDown";
+            this.ImageSizeUpDown.Size = new System.Drawing.Size(77, 21);
+            this.ImageSizeUpDown.TabIndex = 0;
+            this.ImageSizeUpDown.ThousandsSeparator = true;
+            this.ImageSizeUpDown.Value = new decimal(new int[] {
+            512,
             0,
             0,
             0});
@@ -72,50 +77,50 @@ namespace ISCSIConsole
             // lblSize
             // 
             this.lblSize.AutoSize = true;
-            this.lblSize.Location = new System.Drawing.Point(12, 43);
+            this.lblSize.Location = new System.Drawing.Point(12, 66);
             this.lblSize.Name = "lblSize";
-            this.lblSize.Size = new System.Drawing.Size(30, 13);
+            this.lblSize.Size = new System.Drawing.Size(35, 12);
             this.lblSize.TabIndex = 1;
             this.lblSize.Text = "Size:";
             // 
-            // label1
+            // MbLabel
             // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(148, 43);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(23, 13);
-            this.label1.TabIndex = 2;
-            this.label1.Text = "MB";
+            this.MbLabel.AutoSize = true;
+            this.MbLabel.Location = new System.Drawing.Point(189, 66);
+            this.MbLabel.Name = "MbLabel";
+            this.MbLabel.Size = new System.Drawing.Size(17, 12);
+            this.MbLabel.TabIndex = 2;
+            this.MbLabel.Text = "MB";
             // 
             // lblFilePath
             // 
             this.lblFilePath.AutoSize = true;
-            this.lblFilePath.Location = new System.Drawing.Point(12, 18);
+            this.lblFilePath.Location = new System.Drawing.Point(12, 40);
             this.lblFilePath.Name = "lblFilePath";
-            this.lblFilePath.Size = new System.Drawing.Size(26, 13);
+            this.lblFilePath.Size = new System.Drawing.Size(71, 12);
             this.lblFilePath.TabIndex = 3;
-            this.lblFilePath.Text = "File:";
+            this.lblFilePath.Text = "Image File:\r\n";
             // 
-            // txtFilePath
+            // ImageFileTextBox
             // 
-            this.txtFilePath.Location = new System.Drawing.Point(56, 15);
-            this.txtFilePath.Name = "txtFilePath";
-            this.txtFilePath.Size = new System.Drawing.Size(243, 20);
-            this.txtFilePath.TabIndex = 4;
+            this.ImageFileTextBox.Location = new System.Drawing.Point(107, 37);
+            this.ImageFileTextBox.Name = "ImageFileTextBox";
+            this.ImageFileTextBox.Size = new System.Drawing.Size(284, 21);
+            this.ImageFileTextBox.TabIndex = 4;
             // 
-            // btnBrowse
+            // ImageFileButton
             // 
-            this.btnBrowse.Location = new System.Drawing.Point(305, 13);
-            this.btnBrowse.Name = "btnBrowse";
-            this.btnBrowse.Size = new System.Drawing.Size(75, 23);
-            this.btnBrowse.TabIndex = 5;
-            this.btnBrowse.Text = "Browse..";
-            this.btnBrowse.UseVisualStyleBackColor = true;
-            this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
+            this.ImageFileButton.Location = new System.Drawing.Point(397, 35);
+            this.ImageFileButton.Name = "ImageFileButton";
+            this.ImageFileButton.Size = new System.Drawing.Size(75, 23);
+            this.ImageFileButton.TabIndex = 5;
+            this.ImageFileButton.Text = "Browse..";
+            this.ImageFileButton.UseVisualStyleBackColor = true;
+            this.ImageFileButton.Click += new System.EventHandler(this.ImageFileButton_Click);
             // 
             // btnOK
             // 
-            this.btnOK.Location = new System.Drawing.Point(224, 88);
+            this.btnOK.Location = new System.Drawing.Point(164, 161);
             this.btnOK.Name = "btnOK";
             this.btnOK.Size = new System.Drawing.Size(75, 23);
             this.btnOK.TabIndex = 6;
@@ -126,7 +131,7 @@ namespace ISCSIConsole
             // btnCancel
             // 
             this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnCancel.Location = new System.Drawing.Point(305, 88);
+            this.btnCancel.Location = new System.Drawing.Point(245, 161);
             this.btnCancel.Name = "btnCancel";
             this.btnCancel.Size = new System.Drawing.Size(75, 23);
             this.btnCancel.TabIndex = 7;
@@ -134,45 +139,174 @@ namespace ISCSIConsole
             this.btnCancel.UseVisualStyleBackColor = true;
             this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
             // 
+            // FormatLabel
+            // 
+            this.FormatLabel.AutoSize = true;
+            this.FormatLabel.Location = new System.Drawing.Point(12, 14);
+            this.FormatLabel.Name = "FormatLabel";
+            this.FormatLabel.Size = new System.Drawing.Size(47, 12);
+            this.FormatLabel.TabIndex = 1;
+            this.FormatLabel.Text = "Format:";
+            // 
+            // FormatComboBox
+            // 
+            this.FormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.FormatComboBox.FormattingEnabled = true;
+            this.FormatComboBox.Location = new System.Drawing.Point(107, 11);
+            this.FormatComboBox.Name = "FormatComboBox";
+            this.FormatComboBox.Size = new System.Drawing.Size(198, 20);
+            this.FormatComboBox.TabIndex = 8;
+            this.FormatComboBox.SelectedIndexChanged += new System.EventHandler(this.FormatComboBox_SelectedIndexChanged);
+            // 
+            // TypeLabel
+            // 
+            this.TypeLabel.AutoSize = true;
+            this.TypeLabel.Location = new System.Drawing.Point(311, 14);
+            this.TypeLabel.Name = "TypeLabel";
+            this.TypeLabel.Size = new System.Drawing.Size(35, 12);
+            this.TypeLabel.TabIndex = 1;
+            this.TypeLabel.Text = "Type:";
+            // 
+            // TypeComboBox
+            // 
+            this.TypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.TypeComboBox.FormattingEnabled = true;
+            this.TypeComboBox.Location = new System.Drawing.Point(352, 11);
+            this.TypeComboBox.Name = "TypeComboBox";
+            this.TypeComboBox.Size = new System.Drawing.Size(120, 20);
+            this.TypeComboBox.TabIndex = 8;
+            // 
+            // SnapshotLabel
+            // 
+            this.SnapshotLabel.AutoSize = true;
+            this.SnapshotLabel.Location = new System.Drawing.Point(12, 94);
+            this.SnapshotLabel.Name = "SnapshotLabel";
+            this.SnapshotLabel.Size = new System.Drawing.Size(89, 12);
+            this.SnapshotLabel.TabIndex = 3;
+            this.SnapshotLabel.Text = "Snapshot File:";
+            // 
+            // SnapshotTextBox
+            // 
+            this.SnapshotTextBox.Location = new System.Drawing.Point(107, 91);
+            this.SnapshotTextBox.Name = "SnapshotTextBox";
+            this.SnapshotTextBox.Size = new System.Drawing.Size(284, 21);
+            this.SnapshotTextBox.TabIndex = 4;
+            // 
+            // SnapshotButton
+            // 
+            this.SnapshotButton.Location = new System.Drawing.Point(397, 89);
+            this.SnapshotButton.Name = "SnapshotButton";
+            this.SnapshotButton.Size = new System.Drawing.Size(75, 23);
+            this.SnapshotButton.TabIndex = 5;
+            this.SnapshotButton.Text = "Browse..";
+            this.SnapshotButton.UseVisualStyleBackColor = true;
+            this.SnapshotButton.Click += new System.EventHandler(this.SnapshotButton_Click);
+            // 
+            // BlockSizeLabel
+            // 
+            this.BlockSizeLabel.AutoSize = true;
+            this.BlockSizeLabel.Location = new System.Drawing.Point(13, 120);
+            this.BlockSizeLabel.Name = "BlockSizeLabel";
+            this.BlockSizeLabel.Size = new System.Drawing.Size(71, 12);
+            this.BlockSizeLabel.TabIndex = 1;
+            this.BlockSizeLabel.Text = "Block Size:";
+            // 
+            // KbLabel
+            // 
+            this.KbLabel.AutoSize = true;
+            this.KbLabel.Location = new System.Drawing.Point(166, 120);
+            this.KbLabel.Name = "KbLabel";
+            this.KbLabel.Size = new System.Drawing.Size(17, 12);
+            this.KbLabel.TabIndex = 2;
+            this.KbLabel.Text = "KB";
+            // 
+            // AheadLabel
+            // 
+            this.AheadLabel.AutoSize = true;
+            this.AheadLabel.Location = new System.Drawing.Point(203, 120);
+            this.AheadLabel.Name = "AheadLabel";
+            this.AheadLabel.Size = new System.Drawing.Size(77, 12);
+            this.AheadLabel.TabIndex = 9;
+            this.AheadLabel.Text = "____(____KB)";
+            // 
+            // BlockSizeUpDown
+            // 
+            this.BlockSizeUpDown.Items.Add("1024");
+            this.BlockSizeUpDown.Items.Add("512");
+            this.BlockSizeUpDown.Items.Add("256");
+            this.BlockSizeUpDown.Items.Add("128");
+            this.BlockSizeUpDown.Items.Add("64");
+            this.BlockSizeUpDown.Items.Add("32");
+            this.BlockSizeUpDown.Items.Add("16");
+            this.BlockSizeUpDown.Location = new System.Drawing.Point(107, 118);
+            this.BlockSizeUpDown.Name = "BlockSizeUpDown";
+            this.BlockSizeUpDown.ReadOnly = true;
+            this.BlockSizeUpDown.Size = new System.Drawing.Size(55, 21);
+            this.BlockSizeUpDown.TabIndex = 10;
+            this.BlockSizeUpDown.Text = "512";
+            this.BlockSizeUpDown.SelectedItemChanged += new System.EventHandler(this.BlockSizeUpDown_SelectedItemChanged);
+            // 
             // CreateDiskImageForm
             // 
             this.AcceptButton = this.btnOK;
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
             this.CancelButton = this.btnCancel;
-            this.ClientSize = new System.Drawing.Size(394, 125);
+            this.ClientSize = new System.Drawing.Size(484, 211);
+            this.Controls.Add(this.BlockSizeUpDown);
+            this.Controls.Add(this.AheadLabel);
+            this.Controls.Add(this.TypeComboBox);
+            this.Controls.Add(this.FormatComboBox);
             this.Controls.Add(this.btnCancel);
             this.Controls.Add(this.btnOK);
-            this.Controls.Add(this.btnBrowse);
-            this.Controls.Add(this.txtFilePath);
+            this.Controls.Add(this.SnapshotButton);
+            this.Controls.Add(this.ImageFileButton);
+            this.Controls.Add(this.SnapshotTextBox);
+            this.Controls.Add(this.SnapshotLabel);
+            this.Controls.Add(this.ImageFileTextBox);
             this.Controls.Add(this.lblFilePath);
-            this.Controls.Add(this.label1);
+            this.Controls.Add(this.TypeLabel);
+            this.Controls.Add(this.KbLabel);
+            this.Controls.Add(this.MbLabel);
+            this.Controls.Add(this.FormatLabel);
+            this.Controls.Add(this.BlockSizeLabel);
             this.Controls.Add(this.lblSize);
-            this.Controls.Add(this.numericDiskSize);
+            this.Controls.Add(this.ImageSizeUpDown);
             this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
             this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
             this.MaximizeBox = false;
-            this.MaximumSize = new System.Drawing.Size(400, 150);
-            this.MinimumSize = new System.Drawing.Size(400, 150);
+            this.MaximumSize = new System.Drawing.Size(500, 250);
+            this.MinimumSize = new System.Drawing.Size(500, 250);
             this.Name = "CreateDiskImageForm";
+            this.ShowInTaskbar = false;
             this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
             this.Text = "Create Virtual Disk";
             this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CreateDiskImageForm_FormClosing);
-            ((System.ComponentModel.ISupportInitialize)(this.numericDiskSize)).EndInit();
+            this.Shown += new System.EventHandler(this.CreateDiskImageForm_Shown);
+            ((System.ComponentModel.ISupportInitialize)(this.ImageSizeUpDown)).EndInit();
             this.ResumeLayout(false);
             this.PerformLayout();
 
         }
 
         #endregion
-
-        private System.Windows.Forms.SaveFileDialog saveVirtualDiskFileDialog;
-        private System.Windows.Forms.NumericUpDown numericDiskSize;
+        private System.Windows.Forms.NumericUpDown ImageSizeUpDown;
         private System.Windows.Forms.Label lblSize;
-        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label MbLabel;
         private System.Windows.Forms.Label lblFilePath;
-        private System.Windows.Forms.TextBox txtFilePath;
-        private System.Windows.Forms.Button btnBrowse;
+        private System.Windows.Forms.TextBox ImageFileTextBox;
+        private System.Windows.Forms.Button ImageFileButton;
         private System.Windows.Forms.Button btnOK;
         private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.Label FormatLabel;
+        private System.Windows.Forms.ComboBox FormatComboBox;
+        private System.Windows.Forms.Label TypeLabel;
+        private System.Windows.Forms.ComboBox TypeComboBox;
+        private System.Windows.Forms.Label SnapshotLabel;
+        private System.Windows.Forms.TextBox SnapshotTextBox;
+        private System.Windows.Forms.Button SnapshotButton;
+        private System.Windows.Forms.Label BlockSizeLabel;
+        private System.Windows.Forms.Label KbLabel;
+        private System.Windows.Forms.Label AheadLabel;
+        private System.Windows.Forms.DomainUpDown BlockSizeUpDown;
     }
 }

+ 152 - 48
ISCSIConsole/CreateDiskImageForm.cs

@@ -1,107 +1,211 @@
+using DiskAccessLibrary;
 using System;
 using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
 using System.IO;
-using System.Text;
 using System.Threading;
 using System.Windows.Forms;
-using DiskAccessLibrary;
+using static DiskAccessLibrary.Mod.Consts;
 
 namespace ISCSIConsole
 {
     public partial class CreateDiskImageForm : Form
     {
-        private DiskImage m_diskImage;
-        private bool m_isWorking = false;
+
+        private bool m_isWorking;
+
+        private FileDialog _imageFileDialog;
+        private FileDialog _snapshotFileDialog;
+
+        public DiskImage DiskImage { get; private set; }
+
+        private bool SnapshotControlEnabled
+        {
+            set
+            {
+                SnapshotLabel.Enabled = value;
+                SnapshotTextBox.Enabled = value;
+                SnapshotButton.Enabled = value;
+                BlockSizeUpDown.Enabled = value;
+                KbLabel.Enabled = value;
+                AheadLabel.Enabled = value;
+
+                ImageSizeUpDown.Enabled = !value;
+            }
+        }
 
         public CreateDiskImageForm()
         {
             InitializeComponent();
         }
 
-        private void btnCancel_Click(object sender, EventArgs e)
+        private void CreateDiskImageForm_Shown(object sender, EventArgs e)
         {
-            this.DialogResult = DialogResult.Cancel;
-            this.Close();
+            FormatComboBox.DataSource = Enum.GetValues(typeof(DiskImageFormat));
+        }
+
+        private void FormatComboBox_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            var items = new List<DiskImageType>();
+            switch ((DiskImageFormat)FormatComboBox.SelectedValue)
+            {
+                case DiskImageFormat.BlockDifferencingDiskImage:
+                    items.Add(DiskImageType.Differencing);
+                    SnapshotControlEnabled = true;
+
+                    _imageFileDialog = new OpenFileDialog
+                    {
+                        CheckFileExists = true,
+                        Filter = "Raw Disk Image (*.img)|*.img"
+                    };
+
+                    _snapshotFileDialog = new SaveFileDialog
+                    {
+                        Filter = "Block Differencing Disk Image (*.bdd)|*.bdd"
+                    };
+                    break;
+
+                case DiskImageFormat.RawDiskImage:
+                    items.Add(DiskImageType.Fixed);
+                    SnapshotControlEnabled = false;
+                    _imageFileDialog = new SaveFileDialog
+                    {
+                        Filter = "Raw Disk Image (*.img)|*.img"
+                    };
+                    break;
+
+                case DiskImageFormat.VirtualHardDisk:
+                    items.Add(DiskImageType.Dynamic);
+                    items.Add(DiskImageType.Fixed);
+                    SnapshotControlEnabled = false;
+
+                    _imageFileDialog = new SaveFileDialog
+                    {
+                        Filter = "VirtualHardDisk File (*.vhd)|*.vhd"
+                    };
+                    break;
+
+                default:
+                    throw new ArgumentOutOfRangeException();
+            }
+
+            TypeComboBox.DataSource = items;
+        }
+
+        private void ImageFileButton_Click(object sender, EventArgs e)
+        {
+            if (_imageFileDialog.ShowDialog() == DialogResult.OK)
+            {
+                ImageFileTextBox.Text = _imageFileDialog.FileName;
+                if ((DiskImageFormat)FormatComboBox.SelectedValue == DiskImageFormat.BlockDifferencingDiskImage)
+                {
+                    var info = new FileInfo(_imageFileDialog.FileName);
+                    // ReSharper disable once PossibleLossOfFraction
+                    ImageSizeUpDown.Value = info.Length / MegaByte;
+
+                    BlockSizeUpDown_SelectedItemChanged(null, null);
+                }
+            }
+        }
+
+        private void SnapshotButton_Click(object sender, EventArgs e)
+        {
+            if (_snapshotFileDialog.ShowDialog() == DialogResult.OK)
+            {
+                SnapshotTextBox.Text = _snapshotFileDialog.FileName;
+            }
+        }
+
+        private void BlockSizeUpDown_SelectedItemChanged(object sender, EventArgs e)
+        {
+            var blockSize = int.Parse(BlockSizeUpDown.Text) * KiloByte;
+            AheadLabel.Text =
+                $"Init Size:{BddInfo.CalcHeaderSize(ImageFileTextBox.Text, blockSize, out var blocks) / KiloByte:N0} KB" +
+                $", {blocks:N0} Blocks.";
         }
 
         private void btnOK_Click(object sender, EventArgs e)
         {
-            string path = txtFilePath.Text;
-            long size = (long)numericDiskSize.Value * 1024 * 1024;
-            if (path == String.Empty)
+            var format = (DiskImageFormat)FormatComboBox.SelectedValue;
+            var type = (DiskImageType)TypeComboBox.SelectedValue;
+
+            var imgPath = ImageFileTextBox.Text;
+            var imgSize = (long)ImageSizeUpDown.Value * MegaByte;
+
+            var snapshotPath = SnapshotTextBox.Text;
+            var blkSize = int.Parse(BlockSizeUpDown.Text) * KiloByte;
+
+            if (imgPath == string.Empty)
+            {
+                MessageBox.Show("Please choose image file location", "Error");
+                return;
+            }
+
+            if (format == DiskImageFormat.BlockDifferencingDiskImage
+                && string.IsNullOrWhiteSpace(SnapshotTextBox.Text))
             {
-                MessageBox.Show("Please choose file location", "Error");
+                MessageBox.Show("Please choose snapshot file location", "Error");
                 return;
             }
+
             m_isWorking = true;
-            new Thread(delegate()
+            new Thread(delegate ()
             {
                 DiskImage diskImage;
+
                 try
                 {
-                    diskImage = VirtualHardDisk.CreateFixedDisk(path, size);
+                    diskImage = DiskImageCreator.CreateImage(format, type, imgPath, imgSize, snapshotPath, blkSize);
                 }
-                catch (IOException ex)
+                catch (Exception ex)
                 {
-                    this.Invoke((MethodInvoker)delegate()
+                    Invoke((MethodInvoker)delegate
                     {
                         MessageBox.Show("Failed to create the disk: " + ex.Message, "Error");
-                        txtFilePath.Enabled = true;
-                        btnBrowse.Enabled = true;
-                        numericDiskSize.Enabled = true;
+                        ImageFileTextBox.Enabled = true;
+                        ImageFileButton.Enabled = true;
+                        ImageSizeUpDown.Enabled = true;
                         btnOK.Enabled = true;
                         btnCancel.Enabled = true;
                     });
                     m_isWorking = false;
                     return;
                 }
-                bool isLocked = diskImage.ExclusiveLock();
+
+                var isLocked = diskImage.ExclusiveLock();
                 if (!isLocked)
                 {
-                    this.Invoke((MethodInvoker)delegate()
+                    Invoke((MethodInvoker)delegate
                     {
                         MessageBox.Show("Cannot lock the disk image for exclusive access", "Error");
-                        txtFilePath.Enabled = true;
-                        btnBrowse.Enabled = true;
-                        numericDiskSize.Enabled = true;
+                        ImageFileTextBox.Enabled = true;
+                        ImageFileButton.Enabled = true;
+                        ImageSizeUpDown.Enabled = true;
                         btnOK.Enabled = true;
                         btnCancel.Enabled = true;
+                        m_isWorking = false;
                     });
-                    m_isWorking = false;
                     return;
                 }
-                m_diskImage = diskImage;
-                m_isWorking = false;
-                this.Invoke((MethodInvoker)delegate()
+                DiskImage = diskImage;
+                Invoke((MethodInvoker)delegate
                 {
-                    this.DialogResult = DialogResult.OK;
-                    this.Close();
+                    m_isWorking = false;
+                    DialogResult = DialogResult.OK;
+                    Close();
                 });
             }).Start();
-            txtFilePath.Enabled = false;
-            btnBrowse.Enabled = false;
-            numericDiskSize.Enabled = false;
+
+            ImageFileTextBox.Enabled = false;
+            ImageFileButton.Enabled = false;
+            ImageSizeUpDown.Enabled = false;
             btnOK.Enabled = false;
             btnCancel.Enabled = false;
         }
 
-        private void btnBrowse_Click(object sender, EventArgs e)
-        {
-            DialogResult result = saveVirtualDiskFileDialog.ShowDialog();
-            if (result == DialogResult.OK)
-            {
-                txtFilePath.Text = saveVirtualDiskFileDialog.FileName;
-            }
-        }
-
-        public DiskImage DiskImage
+        private void btnCancel_Click(object sender, EventArgs e)
         {
-            get
-            {
-                return m_diskImage;
-            }
+            DialogResult = DialogResult.Cancel;
+            Close();
         }
 
         private void CreateDiskImageForm_FormClosing(object sender, FormClosingEventArgs e)

+ 3 - 6
ISCSIConsole/CreateDiskImageForm.resx

@@ -112,15 +112,12 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <metadata name="saveVirtualDiskFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 17</value>
-  </metadata>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         AAABAAYAAAAAAAEAIAAoIAQAZgAAAICAAAABACAAKAgBAI4gBABAQAAAAQAgAChCAAC2KAUAMDAAAAEA

+ 5 - 4
ISCSIConsole/CreateRAMDiskForm.Designer.cs

@@ -51,7 +51,7 @@ namespace ISCSIConsole
             0,
             0});
             this.numericDiskSize.Name = "numericDiskSize";
-            this.numericDiskSize.Size = new System.Drawing.Size(86, 20);
+            this.numericDiskSize.Size = new System.Drawing.Size(86, 21);
             this.numericDiskSize.TabIndex = 0;
             this.numericDiskSize.ThousandsSeparator = true;
             this.numericDiskSize.Value = new decimal(new int[] {
@@ -65,7 +65,7 @@ namespace ISCSIConsole
             this.lblSize.AutoSize = true;
             this.lblSize.Location = new System.Drawing.Point(12, 18);
             this.lblSize.Name = "lblSize";
-            this.lblSize.Size = new System.Drawing.Size(30, 13);
+            this.lblSize.Size = new System.Drawing.Size(35, 12);
             this.lblSize.TabIndex = 1;
             this.lblSize.Text = "Size:";
             // 
@@ -74,7 +74,7 @@ namespace ISCSIConsole
             this.label1.AutoSize = true;
             this.label1.Location = new System.Drawing.Point(148, 18);
             this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(23, 13);
+            this.label1.Size = new System.Drawing.Size(17, 12);
             this.label1.TabIndex = 2;
             this.label1.Text = "MB";
             // 
@@ -104,7 +104,7 @@ namespace ISCSIConsole
             this.AcceptButton = this.btnOK;
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
             this.CancelButton = this.btnCancel;
-            this.ClientSize = new System.Drawing.Size(394, 125);
+            this.ClientSize = new System.Drawing.Size(384, 111);
             this.Controls.Add(this.btnCancel);
             this.Controls.Add(this.btnOK);
             this.Controls.Add(this.label1);
@@ -116,6 +116,7 @@ namespace ISCSIConsole
             this.MaximumSize = new System.Drawing.Size(400, 150);
             this.MinimumSize = new System.Drawing.Size(400, 150);
             this.Name = "CreateRAMDiskForm";
+            this.ShowInTaskbar = false;
             this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
             this.Text = "Create RAM Disk";
             ((System.ComponentModel.ISupportInitialize)(this.numericDiskSize)).EndInit();

+ 3 - 3
ISCSIConsole/CreateRAMDiskForm.resx

@@ -112,12 +112,12 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         AAABAAYAAAAAAAEAIAAoIAQAZgAAAICAAAABACAAKAgBAI4gBABAQAAAAQAgAChCAAC2KAUAMDAAAAEA

+ 8 - 1
ISCSIConsole/ISCSIConsole.csproj

@@ -1,4 +1,4 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -15,6 +15,8 @@
     <UpgradeBackupLocation>
     </UpgradeBackupLocation>
     <OldToolsVersion>2.0</OldToolsVersion>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <TargetFrameworkProfile />
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -24,6 +26,7 @@
     <DefineConstants>TRACE;DEBUG;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -32,6 +35,7 @@
     <DefineConstants>TRACE;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
@@ -144,6 +148,9 @@
       <Name>Utilities</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 40 - 10
ISCSIConsole/SelectDiskImageForm.Designer.cs

@@ -36,6 +36,8 @@ namespace ISCSIConsole
             this.btnCancel = new System.Windows.Forms.Button();
             this.chkReadOnly = new System.Windows.Forms.CheckBox();
             this.openDiskImageDialog = new System.Windows.Forms.OpenFileDialog();
+            this.DiskInfoLabel = new System.Windows.Forms.Label();
+            this.DiskInfiValueLabel = new System.Windows.Forms.Label();
             this.SuspendLayout();
             // 
             // lblFilePath
@@ -43,20 +45,23 @@ namespace ISCSIConsole
             this.lblFilePath.AutoSize = true;
             this.lblFilePath.Location = new System.Drawing.Point(12, 18);
             this.lblFilePath.Name = "lblFilePath";
-            this.lblFilePath.Size = new System.Drawing.Size(26, 13);
+            this.lblFilePath.Size = new System.Drawing.Size(35, 12);
             this.lblFilePath.TabIndex = 3;
             this.lblFilePath.Text = "File:";
             // 
             // txtFilePath
             // 
+            this.txtFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
             this.txtFilePath.Location = new System.Drawing.Point(56, 15);
             this.txtFilePath.Name = "txtFilePath";
-            this.txtFilePath.Size = new System.Drawing.Size(243, 20);
+            this.txtFilePath.Size = new System.Drawing.Size(328, 21);
             this.txtFilePath.TabIndex = 4;
             // 
             // btnBrowse
             // 
-            this.btnBrowse.Location = new System.Drawing.Point(305, 13);
+            this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnBrowse.Location = new System.Drawing.Point(390, 13);
             this.btnBrowse.Name = "btnBrowse";
             this.btnBrowse.Size = new System.Drawing.Size(75, 23);
             this.btnBrowse.TabIndex = 5;
@@ -66,7 +71,8 @@ namespace ISCSIConsole
             // 
             // btnOK
             // 
-            this.btnOK.Location = new System.Drawing.Point(224, 88);
+            this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnOK.Location = new System.Drawing.Point(309, 182);
             this.btnOK.Name = "btnOK";
             this.btnOK.Size = new System.Drawing.Size(75, 23);
             this.btnOK.TabIndex = 6;
@@ -76,8 +82,9 @@ namespace ISCSIConsole
             // 
             // btnCancel
             // 
+            this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
             this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnCancel.Location = new System.Drawing.Point(305, 88);
+            this.btnCancel.Location = new System.Drawing.Point(390, 182);
             this.btnCancel.Name = "btnCancel";
             this.btnCancel.Size = new System.Drawing.Size(75, 23);
             this.btnCancel.TabIndex = 7;
@@ -87,10 +94,11 @@ namespace ISCSIConsole
             // 
             // chkReadOnly
             // 
+            this.chkReadOnly.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
             this.chkReadOnly.AutoSize = true;
-            this.chkReadOnly.Location = new System.Drawing.Point(12, 92);
+            this.chkReadOnly.Location = new System.Drawing.Point(12, 189);
             this.chkReadOnly.Name = "chkReadOnly";
-            this.chkReadOnly.Size = new System.Drawing.Size(74, 17);
+            this.chkReadOnly.Size = new System.Drawing.Size(78, 16);
             this.chkReadOnly.TabIndex = 8;
             this.chkReadOnly.Text = "Read only";
             this.chkReadOnly.UseVisualStyleBackColor = true;
@@ -99,24 +107,44 @@ namespace ISCSIConsole
             // 
             this.openDiskImageDialog.Filter = resources.GetString("openDiskImageDialog.Filter");
             // 
+            // DiskInfoLabel
+            // 
+            this.DiskInfoLabel.AutoSize = true;
+            this.DiskInfoLabel.Location = new System.Drawing.Point(12, 48);
+            this.DiskInfoLabel.Name = "DiskInfoLabel";
+            this.DiskInfoLabel.Size = new System.Drawing.Size(101, 12);
+            this.DiskInfoLabel.TabIndex = 9;
+            this.DiskInfoLabel.Text = "Disk Image Info:";
+            // 
+            // DiskInfiValueLabel
+            // 
+            this.DiskInfiValueLabel.AutoSize = true;
+            this.DiskInfiValueLabel.Location = new System.Drawing.Point(54, 70);
+            this.DiskInfiValueLabel.Name = "DiskInfiValueLabel";
+            this.DiskInfiValueLabel.Size = new System.Drawing.Size(29, 12);
+            this.DiskInfiValueLabel.TabIndex = 9;
+            this.DiskInfiValueLabel.Text = "____";
+            // 
             // SelectDiskImageForm
             // 
             this.AcceptButton = this.btnOK;
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
             this.CancelButton = this.btnCancel;
-            this.ClientSize = new System.Drawing.Size(394, 125);
+            this.ClientSize = new System.Drawing.Size(469, 208);
+            this.Controls.Add(this.DiskInfiValueLabel);
+            this.Controls.Add(this.DiskInfoLabel);
             this.Controls.Add(this.chkReadOnly);
             this.Controls.Add(this.btnCancel);
             this.Controls.Add(this.btnOK);
             this.Controls.Add(this.btnBrowse);
             this.Controls.Add(this.txtFilePath);
             this.Controls.Add(this.lblFilePath);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
             this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
             this.MaximizeBox = false;
-            this.MaximumSize = new System.Drawing.Size(400, 150);
+            this.MaximumSize = new System.Drawing.Size(500, 500);
             this.MinimumSize = new System.Drawing.Size(400, 150);
             this.Name = "SelectDiskImageForm";
+            this.ShowInTaskbar = false;
             this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
             this.Text = "Select Disk Image";
             this.ResumeLayout(false);
@@ -133,5 +161,7 @@ namespace ISCSIConsole
         private System.Windows.Forms.Button btnCancel;
         private System.Windows.Forms.CheckBox chkReadOnly;
         private System.Windows.Forms.OpenFileDialog openDiskImageDialog;
+        private System.Windows.Forms.Label DiskInfoLabel;
+        private System.Windows.Forms.Label DiskInfiValueLabel;
     }
 }

+ 2 - 5
ISCSIConsole/SelectDiskImageForm.cs

@@ -1,11 +1,7 @@
+using DiskAccessLibrary;
 using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
 using System.IO;
-using System.Text;
 using System.Windows.Forms;
-using DiskAccessLibrary;
 
 namespace ISCSIConsole
 {
@@ -77,6 +73,7 @@ namespace ISCSIConsole
             if (result == DialogResult.OK)
             {
                 txtFilePath.Text = openDiskImageDialog.FileName;
+                DiskInfiValueLabel.Text = DiskImage.GetDiskImageInfo(txtFilePath.Text);
             }
         }
 

+ 5 - 5
ISCSIConsole/SelectDiskImageForm.resx

@@ -112,18 +112,18 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <metadata name="openDiskImageDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+  <metadata name="openDiskImageDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
   <data name="openDiskImageDialog.Filter" xml:space="preserve">
-    <value>All Supported Disk Images (*.vhd,*.vmdk,*.img,*.bin)|*.vhd;*.vmdk;*.img;*.bin|Virtual Hard Disk (*.vhd)|*.vhd|Virtual Machine Disk (*.vmdk)|*.vmdk|Raw Disk Image (*.img,*.bin)|*.img;*.bin|All Files (*.*)|*.*</value>
+    <value>All Supported Disk Images (*.vhd,*.vmdk,*.img,*.bin,*.bdd)|*.vhd;*.vmdk;*.img;*.bin;*.bdd|Virtual Hard Disk (*.vhd)|*.vhd|Virtual Machine Disk (*.vmdk)|*.vmdk|Raw Disk Image (*.img,*.bin)|*.img;*.bin|Block Differencing Disk Image Files (*.bdd)|*.bdd|All Files (*.*)|*.*</value>
   </data>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         AAABAAYAAAAAAAEAIAAoIAQAZgAAAICAAAABACAAKAgBAI4gBABAQAAAAQAgAChCAAC2KAUAMDAAAAEA

+ 3 - 0
ISCSIConsole/app.config

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>

+ 5 - 1
Utilities/Utilities.csproj

@@ -1,4 +1,4 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -14,6 +14,8 @@
     <UpgradeBackupLocation>
     </UpgradeBackupLocation>
     <OldToolsVersion>2.0</OldToolsVersion>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <TargetFrameworkProfile />
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -23,6 +25,7 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -31,6 +34,7 @@
     <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />