Browse Source

commit: No base image bdd; Loadable Ramdisk; TargetName show in device manager

HOME 4 years ago
parent
commit
597078c34d

+ 4 - 1
DiskAccessLibrary/DiskAccessLibrary.csproj

@@ -204,13 +204,16 @@
     <Compile Include="Mod\BlockDifferencingDiskImage\BlockDifferencingDiskImage.cs" />
     <Compile Include="Mod\BlockDifferencingDiskImage\BlockEntryAllocateFlagIndexer.cs" />
     <Compile Include="Mod\BlockDifferencingDiskImage\BlockEntryOffsetIndexer.cs" />
+    <Compile Include="Mod\BlockDifferencingDiskImage\IReadOnlyIndexer.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="Mod\ILoadableRamDisk.cs" />
     <Compile Include="Mod\LargeRamDisk.cs" />
-    <Compile Include="Mod\UnmanagedLargeRamDisk.cs" />
+    <Compile Include="Mod\RAMDisk.cs" />
+    <Compile Include="Mod\UnmanagedGigabyteBlockSeparatedRamDisk.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionEntry.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionEntryCollection.cs" />
     <Compile Include="PartitionTables\GuidPartitionTable\GuidPartitionTable.cs" />

+ 1 - 1
DiskAccessLibrary/Disks/RAMDisk.cs

@@ -11,7 +11,7 @@ using Utilities;
 
 namespace DiskAccessLibrary
 {
-    public class RAMDisk : Disk
+    public partial class RAMDisk : Disk
     {
         public const int BytesPerRAMDiskSector = 512;
 

+ 14 - 6
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BddInfo.cs

@@ -31,7 +31,7 @@ namespace DiskAccessLibrary
             using var reader = new BinaryReader(fs);
 
             int basedPathLength = reader.ReadUInt16(); //2
-            BasedImagePath = Encoding.UTF8.GetString(reader.ReadBytes(basedPathLength)); //N
+            if (basedPathLength != 0) BasedImagePath = Encoding.UTF8.GetString(reader.ReadBytes(basedPathLength)); //N
             BlockSize = reader.ReadInt32(); //4
             NumberOfBlocks = reader.ReadInt32(); //4
 
@@ -39,10 +39,12 @@ namespace DiskAccessLibrary
             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");
+            if (null != BasedImagePath)
+            {
+                var baseInfo = new FileInfo(BasedImagePath);
+                if (snapMatchLength != baseInfo.Length)
+                    throw new InvalidDataException("Snapshot size no match to based image");
+            }
 
             EntryTableOffset = fs.Position;
 
@@ -59,7 +61,6 @@ namespace DiskAccessLibrary
             Offset = new BlockEntryOffsetIndexer(arr);
         }
 
-
         public static int CalcHeaderSize(string basedImagePath, int blockSize, out int blocks)
         {
             var baseLength = new FileInfo(basedImagePath).Length;
@@ -67,5 +68,12 @@ namespace DiskAccessLibrary
 
             return 2 + Encoding.UTF8.GetByteCount(basedImagePath) + 8 + blocks * BlockIndexEntrySize;
         }
+
+        public static int CalcHeaderSize(long baseLength, int blockSize, out int blocks)
+        {
+            blocks = (int)(baseLength / blockSize);
+
+            return 2 + +8 + blocks * BlockIndexEntrySize;
+        }
     }
 }

+ 55 - 16
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BlockDifferencingDiskImage.cs

@@ -1,4 +1,5 @@
-using System;
+using DiskAccessLibrary.Mod.BlockDifferencingDiskImage;
+using System;
 using System.IO;
 using System.Security.Authentication;
 using System.Text;
@@ -11,6 +12,13 @@ namespace DiskAccessLibrary
 
         private BddInfo BddInfo { get; }
 
+        public bool IsNoBaseImage => null == _basedFileStream;
+
+        public int NumberOfBlocks => BddInfo.NumberOfBlocks;
+        public int BlockSize => BddInfo.BlockSize;
+
+        public IReadOnlyIndexer<int, bool> IsBlockAllocated { get; }
+
         private bool _isExclusiveLock;
 
         private FileStream _basedFileStream;
@@ -22,21 +30,25 @@ namespace DiskAccessLibrary
 
             if (isReadOnly)
             {
-                _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
+                if (null != BddInfo.BasedImagePath) _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
                 _snapshotFileStream = File.OpenRead(Path);
+
+                IsBlockAllocated = new IReadOnlyIndexer<int, bool>(i => BddInfo.Allocated[i]);
             }
             else
             {
-                _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
+                if (null != BddInfo.BasedImagePath) _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)
+        public void ReadBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset)
         {
             if (false == BddInfo.Allocated[blockIndex])
             {
+                if (null == _basedFileStream) return;
+
                 _basedFileStream.Position = (long)blockIndex * BddInfo.BlockSize + blockOffset;
 
                 while (count > 0)
@@ -72,14 +84,18 @@ namespace DiskAccessLibrary
                 {
                     var readCount = blockOffset;
                     var bufLeading = new byte[readCount];
-                    _basedFileStream.Position = (long)blockIndex * BddInfo.BlockSize;
 
-                    var readOffset = 0;
-                    while (readCount > 0)
+                    if (null != _basedFileStream)
                     {
-                        var read = _basedFileStream.Read(bufLeading, readOffset, readCount);
-                        readOffset += read;
-                        readCount -= read;
+                        _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];
@@ -96,14 +112,17 @@ namespace DiskAccessLibrary
                     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)
+                    if (null != _basedFileStream)
                     {
-                        var read = _basedFileStream.Read(bufSuffix, readOffset, readCount);
-                        readOffset += read;
-                        readCount -= read;
+                        _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;
@@ -196,6 +215,26 @@ namespace DiskAccessLibrary
             return true;
         }
 
+        public static BlockDifferencingDiskImage Create(string snapshot, long size, int blockSize)
+        {
+            var numberOfBlocks = (int)Math.DivRem(size, blockSize, out var rem);
+            if (rem != 0) throw new ArgumentException("Size no align to blockSize");
+
+            using var stream = File.Create(snapshot);
+            using var writer = new BinaryWriter(stream);
+
+            writer.Write((ushort)0);
+            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 static BlockDifferencingDiskImage Create(string based, string snapshot, int blockSize)
         {
             var fileInfo = new FileInfo(based);

+ 17 - 0
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/IReadOnlyIndexer.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DiskAccessLibrary.Mod.BlockDifferencingDiskImage
+{
+    public class IReadOnlyIndexer<TI, TV>
+    {
+        private readonly Func<TI, TV> _func;
+
+        public IReadOnlyIndexer(Func<TI, TV> _func) => this._func = _func;
+
+        public TV this[TI index] => _func(index);
+    }
+}

+ 20 - 10
DiskAccessLibrary/Mod/DiskImage.cs

@@ -28,29 +28,39 @@ namespace DiskAccessLibrary
                         var rawLength = new FileInfo(path).Length;
                         info.AppendLine("Raw Disk Image");
                         info.AppendLine($"Size:  {rawLength / MegaByte:N0} MB");
-
                         break;
                     case ".bdd":
                         info.AppendLine("Block Differencing Disk Image");
                         var bdd = new BddInfo(path, false);
 
-                        if (false == File.Exists(bdd.BasedImagePath))
+                        if (null == bdd.BasedImagePath)
                         {
-                            info.AppendLine("** Based image file not found **");
-                            info.AppendLine($"Based on: {bdd.BasedImagePath}");
-                            break;
+                            info.AppendLine("** No Base Image Mode **");
                         }
+                        else
+                        {
+                            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;
+                            var baseLength = new FileInfo(bdd.BasedImagePath).Length;
+
+                            info.AppendLine($"Based on:    {bdd.BasedImagePath}");
+                            info.AppendLine($"Based Size:  {baseLength / MegaByte:N0} MB");
+                            if (baseLength != bdd.Length)
+                            {
+                                info.AppendLine("** Fully Size not match to base **");
+                                break;
+                            }
+                        }
 
-                        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;
                 }
             }

+ 9 - 3
DiskAccessLibrary/Mod/DiskImageCreator.cs

@@ -9,11 +9,17 @@ namespace DiskAccessLibrary
             switch (format)
             {
                 case DiskImageFormat.BlockDifferencingDiskImage:
+                    switch (type)
+                    {
+                        case DiskImageType.Differencing:
+                            return BlockDifferencingDiskImage.Create(imagePath, snapshotPath, blockSize);
 
-                    if (type != DiskImageType.Differencing) throw new NotSupportedException();
-
-                    return BlockDifferencingDiskImage.Create(imagePath, snapshotPath, blockSize);
+                        case DiskImageType.Dynamic:
+                            return BlockDifferencingDiskImage.Create(snapshotPath, imageSize, blockSize);
 
+                        default:
+                            throw new ArgumentOutOfRangeException(nameof(type), type, null);
+                    }
                 case DiskImageFormat.RawDiskImage:
 
                     if (type != DiskImageType.Fixed) throw new NotSupportedException();

+ 13 - 0
DiskAccessLibrary/Mod/ILoadableRamDisk.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DiskAccessLibrary.Mod
+{
+    public interface ILoadableRamDisk
+    {
+        void WriteData(long rawOffset, byte[] data);
+    }
+}

+ 13 - 0
DiskAccessLibrary/Mod/RAMDisk.cs

@@ -0,0 +1,13 @@
+using DiskAccessLibrary.Mod;
+using System;
+
+namespace DiskAccessLibrary
+{
+    public partial class RAMDisk : ILoadableRamDisk
+    {
+        public void WriteData(long rawOffset, byte[] data)
+        {
+            Buffer.BlockCopy(data, 0, m_diskBytes, (int)rawOffset, data.Length);
+        }
+    }
+}

+ 23 - 19
DiskAccessLibrary/Mod/UnmanagedLargeRamDisk.cs

@@ -3,14 +3,14 @@ using System.Runtime.InteropServices;
 
 namespace DiskAccessLibrary.Mod
 {
-    public class UnmanagedLargeRamDisk : Disk
+    public class UnmanagedGigabyteBlockSeparatedRamDisk : Disk, ILoadableRamDisk
     {
         private const int SectorSize = 512;
         private const int BlockSize = Consts.Gigabyte;
 
         private IntPtr[] _blocks;
 
-        public UnmanagedLargeRamDisk(int sizeInGigabyte)
+        public UnmanagedGigabyteBlockSeparatedRamDisk(int sizeInGigabyte)
         {
             _blocks = new IntPtr[sizeInGigabyte];
             Size = (long)sizeInGigabyte * Consts.Gigabyte;
@@ -45,6 +45,26 @@ namespace DiskAccessLibrary.Mod
             Marshal.Copy(buffer, offset, _blocks[blockIndex] + blockOffset, count);
         }
 
+        public void WriteData(long rawOffset, byte[] data)
+        {
+            for (var i = 0; i < data.Length;)
+            {
+                var blockIndex = (int)(rawOffset / BlockSize);
+                var blockOffset = (int)(rawOffset % BlockSize);
+                var bytesToWrite = BlockSize - blockOffset;
+
+                if (i + bytesToWrite > data.Length)
+                {
+                    bytesToWrite = data.Length - i;
+                }
+
+                WriteBlock(data, i, bytesToWrite, blockIndex, blockOffset);
+
+                i += bytesToWrite;
+                rawOffset += bytesToWrite;
+            }
+        }
+
         public override byte[] ReadSectors(long sectorIndex, int sectorCount)
         {
             var rawOffset = sectorIndex * SectorSize;
@@ -75,23 +95,7 @@ namespace DiskAccessLibrary.Mod
         public override void WriteSectors(long sectorIndex, byte[] data)
         {
             var rawOffset = sectorIndex * SectorSize;
-
-            for (var i = 0; i < data.Length;)
-            {
-                var blockIndex = (int)(rawOffset / BlockSize);
-                var blockOffset = (int)(rawOffset % BlockSize);
-                var bytesToWrite = BlockSize - blockOffset;
-
-                if (i + bytesToWrite > data.Length)
-                {
-                    bytesToWrite = data.Length - i;
-                }
-
-                WriteBlock(data, i, bytesToWrite, blockIndex, blockOffset);
-
-                i += bytesToWrite;
-                rawOffset += bytesToWrite;
-            }
+            WriteData(rawOffset, data);
         }
 
         public override int BytesPerSector => SectorSize;

+ 1 - 1
ISCSI/ISCSI.Server/ISCSITarget.cs

@@ -26,7 +26,7 @@ namespace ISCSI.Server
         public event EventHandler<TextRequestArgs> OnTextRequest;
         public event EventHandler<SessionTerminationArgs> OnSessionTermination;
 
-        public ISCSITarget(string targetName, List<Disk> disks) : this(targetName, new VirtualSCSITarget(disks))
+        public ISCSITarget(string targetName, List<Disk> disks) : this(targetName, new VirtualSCSITarget(targetName, disks))
         {
         }
 

+ 1 - 0
ISCSI/ISCSI.csproj

@@ -95,6 +95,7 @@
     <Compile Include="ISCSI.Server\TargetList.cs" />
     <Compile Include="ISCSI.Server\TargetResponseHelper.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SCSITarget\Mod\ISCSI\SCSITarget\VirtualSCSITarget.cs" />
     <Compile Include="SCSI\Enums\AddressingMethod.cs" />
     <Compile Include="SCSI\Enums\ModePageCodeName.cs" />
     <Compile Include="SCSI\Enums\PeripheralDeviceType.cs" />

+ 15 - 0
ISCSI/SCSITarget/Mod/ISCSI/SCSITarget/VirtualSCSITarget.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace SCSI
+{
+    public partial class VirtualSCSITarget
+    {
+        private readonly string _targetName;
+
+        public VirtualSCSITarget(string targetName, List<Disk> disks) : this(disks)
+        {
+            var parts = targetName.Split(new[] { ':' }, 2);
+            _targetName = parts.Length == 2 ? parts[1] : "NoName";
+        }
+    }
+}

+ 3 - 3
ISCSI/SCSITarget/VirtualSCSITarget.cs

@@ -15,7 +15,7 @@ using Utilities;
 
 namespace SCSI
 {
-    public class VirtualSCSITarget : SCSITarget
+    public partial class VirtualSCSITarget : SCSITarget
     {
         private List<Disk> m_disks;
 
@@ -36,7 +36,7 @@ namespace SCSI
             {
                 command = SCSICommandDescriptorBlock.FromBytes(commandBytes, 0);
             }
-            catch(UnsupportedSCSICommandException)
+            catch (UnsupportedSCSICommandException)
             {
                 Log(Severity.Error, "Unsupported SCSI Command (0x{0})", commandBytes[0].ToString("X"));
                 response = FormatSenseData(SenseDataParameter.GetIllegalRequestUnsupportedCommandCodeSenseData());
@@ -136,7 +136,7 @@ namespace SCSI
                     StandardInquiryData inquiryData = new StandardInquiryData();
                     inquiryData.PeripheralDeviceType = 0; // Direct access block device
                     inquiryData.VendorIdentification = "TalAloni";
-                    inquiryData.ProductIdentification = "iSCSI Disk " + lun.ToString();
+                    inquiryData.ProductIdentification = "iSCSI " + _targetName;
                     inquiryData.ProductRevisionLevel = "1.00";
                     inquiryData.DriveSerialNumber = 0;
                     inquiryData.CmdQue = true;

+ 2 - 1
ISCSIConsole/AddTargetForm.cs

@@ -6,6 +6,7 @@ using System.IO;
 using System.Text;
 using System.Windows.Forms;
 using DiskAccessLibrary;
+using DiskAccessLibrary.Mod;
 using ISCSI.Server;
 using Utilities;
 
@@ -106,7 +107,7 @@ namespace ISCSIConsole
             {
                 description = ((DiskImage)disk).Path;
             }
-            else if (disk is RAMDisk)
+            else if (disk is RAMDisk || disk is UnmanagedGigabyteBlockSeparatedRamDisk)
             {
                 description = "RAM Disk";
             }

+ 12 - 10
ISCSIConsole/CreateDiskImageForm.Designer.cs

@@ -32,7 +32,7 @@ namespace ISCSIConsole
             this.ImageSizeUpDown = new System.Windows.Forms.NumericUpDown();
             this.lblSize = new System.Windows.Forms.Label();
             this.MbLabel = new System.Windows.Forms.Label();
-            this.lblFilePath = new System.Windows.Forms.Label();
+            this.ImageFileLabel = new System.Windows.Forms.Label();
             this.ImageFileTextBox = new System.Windows.Forms.TextBox();
             this.ImageFileButton = new System.Windows.Forms.Button();
             this.btnOK = new System.Windows.Forms.Button();
@@ -73,6 +73,7 @@ namespace ISCSIConsole
             0,
             0,
             0});
+            this.ImageSizeUpDown.ValueChanged += new System.EventHandler(this.ImageSizeUpDown_ValueChanged);
             // 
             // lblSize
             // 
@@ -92,14 +93,14 @@ namespace ISCSIConsole
             this.MbLabel.TabIndex = 2;
             this.MbLabel.Text = "MB";
             // 
-            // lblFilePath
+            // ImageFileLabel
             // 
-            this.lblFilePath.AutoSize = true;
-            this.lblFilePath.Location = new System.Drawing.Point(12, 40);
-            this.lblFilePath.Name = "lblFilePath";
-            this.lblFilePath.Size = new System.Drawing.Size(71, 12);
-            this.lblFilePath.TabIndex = 3;
-            this.lblFilePath.Text = "Image File:\r\n";
+            this.ImageFileLabel.AutoSize = true;
+            this.ImageFileLabel.Location = new System.Drawing.Point(12, 40);
+            this.ImageFileLabel.Name = "ImageFileLabel";
+            this.ImageFileLabel.Size = new System.Drawing.Size(71, 12);
+            this.ImageFileLabel.TabIndex = 3;
+            this.ImageFileLabel.Text = "Image File:\r\n";
             // 
             // ImageFileTextBox
             // 
@@ -175,6 +176,7 @@ namespace ISCSIConsole
             this.TypeComboBox.Name = "TypeComboBox";
             this.TypeComboBox.Size = new System.Drawing.Size(120, 20);
             this.TypeComboBox.TabIndex = 8;
+            this.TypeComboBox.SelectedIndexChanged += new System.EventHandler(this.TypeComboBox_SelectedIndexChanged);
             // 
             // SnapshotLabel
             // 
@@ -263,7 +265,7 @@ namespace ISCSIConsole
             this.Controls.Add(this.SnapshotTextBox);
             this.Controls.Add(this.SnapshotLabel);
             this.Controls.Add(this.ImageFileTextBox);
-            this.Controls.Add(this.lblFilePath);
+            this.Controls.Add(this.ImageFileLabel);
             this.Controls.Add(this.TypeLabel);
             this.Controls.Add(this.KbLabel);
             this.Controls.Add(this.MbLabel);
@@ -292,7 +294,7 @@ namespace ISCSIConsole
         private System.Windows.Forms.NumericUpDown ImageSizeUpDown;
         private System.Windows.Forms.Label lblSize;
         private System.Windows.Forms.Label MbLabel;
-        private System.Windows.Forms.Label lblFilePath;
+        private System.Windows.Forms.Label ImageFileLabel;
         private System.Windows.Forms.TextBox ImageFileTextBox;
         private System.Windows.Forms.Button ImageFileButton;
         private System.Windows.Forms.Button btnOK;

+ 57 - 5
ISCSIConsole/CreateDiskImageForm.cs

@@ -10,7 +10,6 @@ namespace ISCSIConsole
 {
     public partial class CreateDiskImageForm : Form
     {
-
         private bool m_isWorking;
 
         private FileDialog _imageFileDialog;
@@ -33,6 +32,17 @@ namespace ISCSIConsole
             }
         }
 
+        private bool NoBaseImageControlEnable
+        {
+            set
+            {
+                ImageFileLabel.Enabled = !value;
+                ImageFileTextBox.Enabled = !value;
+                ImageFileButton.Enabled = !value;
+                ImageSizeUpDown.Enabled = value;
+            }
+        }
+
         public CreateDiskImageForm()
         {
             InitializeComponent();
@@ -50,6 +60,7 @@ namespace ISCSIConsole
             {
                 case DiskImageFormat.BlockDifferencingDiskImage:
                     items.Add(DiskImageType.Differencing);
+                    items.Add(DiskImageType.Dynamic);
                     SnapshotControlEnabled = true;
 
                     _imageFileDialog = new OpenFileDialog
@@ -91,6 +102,24 @@ namespace ISCSIConsole
             TypeComboBox.DataSource = items;
         }
 
+        private void TypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            var format = (DiskImageFormat)FormatComboBox.SelectedValue;
+            if (format == DiskImageFormat.BlockDifferencingDiskImage)
+            {
+                switch ((DiskImageType)TypeComboBox.SelectedValue)
+                {
+                    case DiskImageType.Dynamic:
+                        NoBaseImageControlEnable = true;
+                        break;
+
+                    default:
+                        NoBaseImageControlEnable = false;
+                        break;
+                }
+            }
+        }
+
         private void ImageFileButton_Click(object sender, EventArgs e)
         {
             if (_imageFileDialog.ShowDialog() == DialogResult.OK)
@@ -115,12 +144,35 @@ namespace ISCSIConsole
             }
         }
 
+        private void ImageSizeUpDown_ValueChanged(object sender, EventArgs e)
+        {
+            UpdateSnapshotInfo();
+        }
+
         private void BlockSizeUpDown_SelectedItemChanged(object sender, EventArgs e)
         {
+            UpdateSnapshotInfo();
+        }
+
+        private void UpdateSnapshotInfo()
+        {
+            var format = (DiskImageFormat)FormatComboBox.SelectedValue;
+            var type = (DiskImageType)TypeComboBox.SelectedValue;
+
             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.";
+
+            if (format == DiskImageFormat.BlockDifferencingDiskImage && type == DiskImageType.Dynamic)
+            {
+                AheadLabel.Text =
+                    $"Init Size:{BddInfo.CalcHeaderSize((long)(ImageSizeUpDown.Value * MegaByte), blockSize, out var blocks) / KiloByte:N0} KB" +
+                    $", {blocks:N0} Blocks.";
+            }
+            else
+            {
+                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)
@@ -134,7 +186,7 @@ namespace ISCSIConsole
             var snapshotPath = SnapshotTextBox.Text;
             var blkSize = int.Parse(BlockSizeUpDown.Text) * KiloByte;
 
-            if (imgPath == string.Empty)
+            if ((format != DiskImageFormat.BlockDifferencingDiskImage && type != DiskImageType.Dynamic) && imgPath == string.Empty)
             {
                 MessageBox.Show("Please choose image file location", "Error");
                 return;

+ 75 - 6
ISCSIConsole/CreateRAMDiskForm.Designer.cs

@@ -35,6 +35,12 @@ namespace ISCSIConsole
             this.btnCancel = new System.Windows.Forms.Button();
             this.MbRadioButton = new System.Windows.Forms.RadioButton();
             this.GbRadioButton = new System.Windows.Forms.RadioButton();
+            this.BaseOnCheckBox = new System.Windows.Forms.CheckBox();
+            this.ImageFileButton = new System.Windows.Forms.Button();
+            this.ImageFileTextBox = new System.Windows.Forms.TextBox();
+            this.DiskInfiValueLabel = new System.Windows.Forms.Label();
+            this.DiskInfoLabel = new System.Windows.Forms.Label();
+            this.openDiskImageDialog = new System.Windows.Forms.OpenFileDialog();
             ((System.ComponentModel.ISupportInitialize)(this.numericDiskSize)).BeginInit();
             this.SuspendLayout();
             // 
@@ -56,7 +62,7 @@ namespace ISCSIConsole
             this.numericDiskSize.TabIndex = 0;
             this.numericDiskSize.ThousandsSeparator = true;
             this.numericDiskSize.Value = new decimal(new int[] {
-            100,
+            512,
             0,
             0,
             0});
@@ -72,7 +78,7 @@ namespace ISCSIConsole
             // 
             // btnOK
             // 
-            this.btnOK.Location = new System.Drawing.Point(224, 88);
+            this.btnOK.Location = new System.Drawing.Point(326, 187);
             this.btnOK.Name = "btnOK";
             this.btnOK.Size = new System.Drawing.Size(75, 23);
             this.btnOK.TabIndex = 6;
@@ -83,7 +89,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(407, 187);
             this.btnCancel.Name = "btnCancel";
             this.btnCancel.Size = new System.Drawing.Size(75, 23);
             this.btnCancel.TabIndex = 7;
@@ -113,12 +119,69 @@ namespace ISCSIConsole
             this.GbRadioButton.Text = "GB";
             this.GbRadioButton.UseVisualStyleBackColor = true;
             // 
+            // BaseOnCheckBox
+            // 
+            this.BaseOnCheckBox.AutoSize = true;
+            this.BaseOnCheckBox.Location = new System.Drawing.Point(14, 44);
+            this.BaseOnCheckBox.Name = "BaseOnCheckBox";
+            this.BaseOnCheckBox.Size = new System.Drawing.Size(66, 16);
+            this.BaseOnCheckBox.TabIndex = 10;
+            this.BaseOnCheckBox.Text = "BaseOn:";
+            this.BaseOnCheckBox.UseVisualStyleBackColor = true;
+            this.BaseOnCheckBox.CheckedChanged += new System.EventHandler(this.BaseOnCheckBox_CheckedChanged);
+            // 
+            // ImageFileButton
+            // 
+            this.ImageFileButton.Enabled = false;
+            this.ImageFileButton.Location = new System.Drawing.Point(397, 40);
+            this.ImageFileButton.Name = "ImageFileButton";
+            this.ImageFileButton.Size = new System.Drawing.Size(75, 23);
+            this.ImageFileButton.TabIndex = 12;
+            this.ImageFileButton.Text = "Browse..";
+            this.ImageFileButton.UseVisualStyleBackColor = true;
+            this.ImageFileButton.Click += new System.EventHandler(this.ImageFileButton_Click);
+            // 
+            // ImageFileTextBox
+            // 
+            this.ImageFileTextBox.Enabled = false;
+            this.ImageFileTextBox.Location = new System.Drawing.Point(86, 42);
+            this.ImageFileTextBox.Name = "ImageFileTextBox";
+            this.ImageFileTextBox.Size = new System.Drawing.Size(305, 21);
+            this.ImageFileTextBox.TabIndex = 11;
+            // 
+            // DiskInfiValueLabel
+            // 
+            this.DiskInfiValueLabel.AutoSize = true;
+            this.DiskInfiValueLabel.Location = new System.Drawing.Point(54, 88);
+            this.DiskInfiValueLabel.Name = "DiskInfiValueLabel";
+            this.DiskInfiValueLabel.Size = new System.Drawing.Size(29, 12);
+            this.DiskInfiValueLabel.TabIndex = 13;
+            this.DiskInfiValueLabel.Text = "____";
+            // 
+            // DiskInfoLabel
+            // 
+            this.DiskInfoLabel.AutoSize = true;
+            this.DiskInfoLabel.Location = new System.Drawing.Point(12, 66);
+            this.DiskInfoLabel.Name = "DiskInfoLabel";
+            this.DiskInfoLabel.Size = new System.Drawing.Size(215, 12);
+            this.DiskInfoLabel.TabIndex = 14;
+            this.DiskInfoLabel.Text = "Disk Image Info (only dynamic bdd):";
+            // 
+            // openDiskImageDialog
+            // 
+            this.openDiskImageDialog.Filter = "Block Differencing Disk Image Files (*.bdd)|*.bdd";
+            // 
             // CreateRAMDiskForm
             // 
             this.AcceptButton = this.btnOK;
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
             this.CancelButton = this.btnCancel;
-            this.ClientSize = new System.Drawing.Size(384, 111);
+            this.ClientSize = new System.Drawing.Size(484, 211);
+            this.Controls.Add(this.DiskInfiValueLabel);
+            this.Controls.Add(this.DiskInfoLabel);
+            this.Controls.Add(this.ImageFileButton);
+            this.Controls.Add(this.ImageFileTextBox);
+            this.Controls.Add(this.BaseOnCheckBox);
             this.Controls.Add(this.GbRadioButton);
             this.Controls.Add(this.MbRadioButton);
             this.Controls.Add(this.btnCancel);
@@ -128,8 +191,8 @@ namespace ISCSIConsole
             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 = "CreateRAMDiskForm";
             this.ShowInTaskbar = false;
             this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
@@ -148,5 +211,11 @@ namespace ISCSIConsole
         private System.Windows.Forms.Button btnCancel;
         private System.Windows.Forms.RadioButton MbRadioButton;
         private System.Windows.Forms.RadioButton GbRadioButton;
+        private System.Windows.Forms.CheckBox BaseOnCheckBox;
+        private System.Windows.Forms.Button ImageFileButton;
+        private System.Windows.Forms.TextBox ImageFileTextBox;
+        private System.Windows.Forms.Label DiskInfiValueLabel;
+        private System.Windows.Forms.Label DiskInfoLabel;
+        private System.Windows.Forms.OpenFileDialog openDiskImageDialog;
     }
 }

+ 83 - 16
ISCSIConsole/CreateRAMDiskForm.cs

@@ -1,14 +1,12 @@
 using DiskAccessLibrary;
+using DiskAccessLibrary.Mod;
 using System;
 using System.Windows.Forms;
-using DiskAccessLibrary.Mod;
 
 namespace ISCSIConsole
 {
     public partial class CreateRAMDiskForm : Form
     {
-        private Disk m_ramDisk;
-
         public CreateRAMDiskForm()
         {
             InitializeComponent();
@@ -16,15 +14,72 @@ namespace ISCSIConsole
 
         private void btnCancel_Click(object sender, EventArgs e)
         {
-            this.DialogResult = DialogResult.Cancel;
-            this.Close();
+            DialogResult = DialogResult.Cancel;
+            Close();
+        }
+
+        private void BaseOnCheckBox_CheckedChanged(object sender, EventArgs e)
+        {
+            ImageFileTextBox.Enabled = BaseOnCheckBox.Checked;
+            ImageFileButton.Enabled = BaseOnCheckBox.Checked;
+        }
+
+        private void ImageFileButton_Click(object sender, EventArgs e)
+        {
+            DialogResult result = openDiskImageDialog.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                ImageFileTextBox.Text = openDiskImageDialog.FileName;
+                DiskInfiValueLabel.Text = DiskImage.GetDiskImageInfo(ImageFileTextBox.Text);
+            }
         }
 
         private void btnOK_Click(object sender, EventArgs e)
         {
+            BlockDifferencingDiskImage bdd = null;
+            if (BaseOnCheckBox.Checked) // check size
+            {
+                if (string.IsNullOrWhiteSpace(ImageFileTextBox.Text))
+                {
+                    MessageBox.Show("Please choose file location.", "Error");
+                    return;
+                }
+
+                bdd = new BlockDifferencingDiskImage(ImageFileTextBox.Text, true);
+
+                if (false == bdd.IsNoBaseImage)
+                {
+                    MessageBox.Show("Only ** No Base Image Mode ** supported");
+                    return;
+                }
+
+                long diskSize;
+                if (MbRadioButton.Checked)
+                {
+                    diskSize = (int)numericDiskSize.Value * Consts.MegaByte;
+                }
+                else if (GbRadioButton.Checked)
+                {
+                    diskSize = (long)numericDiskSize.Value * Consts.Gigabyte;
+                }
+                else
+                {
+                    MessageBox.Show("What chosen?");
+                    return;
+                }
+
+                if (diskSize < bdd.Size)
+                {
+                    MessageBox.Show("Ram disk size too small to load file");
+                    return;
+                }
+            }
+
+            ILoadableRamDisk loadableRamDisk;
+
             if (MbRadioButton.Checked)
             {
-                var size = (int)numericDiskSize.Value * 1024 * 1024;
+                var size = (int)numericDiskSize.Value * Consts.MegaByte;
                 RAMDisk disk;
                 try
                 {
@@ -35,12 +90,13 @@ namespace ISCSIConsole
                     MessageBox.Show("Not enough memory available", "Error");
                     return;
                 }
-                m_ramDisk = disk;
+                RAMDisk = disk;
+                loadableRamDisk = disk;
             }
             else if (GbRadioButton.Checked)
             {
                 var size = (int)numericDiskSize.Value;
-                UnmanagedLargeRamDisk disk = new UnmanagedLargeRamDisk(size); ;
+                var disk = new UnmanagedGigabyteBlockSeparatedRamDisk(size); ;
                 try
                 {
                     disk.Allocate();
@@ -51,23 +107,34 @@ namespace ISCSIConsole
                     MessageBox.Show("Not enough memory available", "Error");
                     return;
                 }
-                m_ramDisk = disk;
+                RAMDisk = disk;
+                loadableRamDisk = disk;
             }
             else
             {
                 MessageBox.Show("What chosen?");
                 return;
             }
-            this.DialogResult = DialogResult.OK;
-            this.Close();
-        }
 
-        public Disk RAMDisk
-        {
-            get
+            if (null != bdd) //Load in to ram disk
             {
-                return m_ramDisk;
+                var buffer = new byte[bdd.BlockSize];
+                for (var i = 0; i < bdd.NumberOfBlocks; i++)
+                {
+                    if (false == bdd.IsBlockAllocated[i]) continue;
+
+                    bdd.ReadBlock(buffer, 0, buffer.Length, i, 0);
+
+                    loadableRamDisk.WriteData(i * bdd.BlockSize, buffer);
+                }
+
+                bdd.ReleaseLock();
             }
+
+            DialogResult = DialogResult.OK;
+            Close();
         }
+
+        public Disk RAMDisk { get; private set; }
     }
 }

+ 3 - 0
ISCSIConsole/CreateRAMDiskForm.resx

@@ -117,6 +117,9 @@
   <resheader name="writer">
     <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=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
   <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>

+ 2 - 2
ISCSIConsole/Helpers/LockUtils.cs

@@ -36,9 +36,9 @@ namespace ISCSIConsole
             {
                 ((LargeRamDisk)disk).Free();
             }
-            else if (disk is UnmanagedLargeRamDisk)
+            else if (disk is UnmanagedGigabyteBlockSeparatedRamDisk)
             {
-                ((UnmanagedLargeRamDisk)disk).Free();
+                ((UnmanagedGigabyteBlockSeparatedRamDisk)disk).Free();
             }
 #if Win32
             else if (disk is PhysicalDisk)