Browse Source

commit: enable write on base image of bdd; allow hot clean bdd if based on image

HOME 3 years ago
parent
commit
4c17da4aab

+ 2 - 2
DiskAccessLibrary/Disks/RawDiskImage/RawDiskImage.cs

@@ -106,7 +106,7 @@ namespace DiskAccessLibrary
             {
                 flags |= (uint)FILE_FLAG_OVERLAPPED;
             }
-            Microsoft.Win32.SafeHandles.SafeFileHandle handle = HandleUtils.GetFileHandle(this.Path, fileAccess, ShareMode.Read, flags);
+            Microsoft.Win32.SafeHandles.SafeFileHandle handle = HandleUtils.GetFileHandle(this.Path, fileAccess, ShareMode.ReadWrite, flags);
             if (!handle.IsInvalid)
             {
                 return new FileStreamEx(handle, fileAccess);
@@ -120,7 +120,7 @@ namespace DiskAccessLibrary
                 return null; // this line will not be reached
             }
 #else
-            return new FileStream(this.Path, FileMode.Open, fileAccess, FileShare.Read, m_bytesPerSector, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
+            return new FileStream(this.Path, FileMode.Open, fileAccess, FileShare.ReadWrite, m_bytesPerSector, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
 #endif
         }
 

+ 3 - 1
DiskAccessLibrary/Mod/BlockDifferencingDiskImage/BddInfo.cs

@@ -9,6 +9,7 @@ namespace DiskAccessLibrary
         public const int BlockIndexEntrySize = 8;
 
         public string BasedImagePath { get; }
+        public string SnapshotImagePath { get; }
 
         public long Length { get; }
 
@@ -27,6 +28,7 @@ namespace DiskAccessLibrary
 
         public BddInfo(string snapshotImagePath, bool readEntries = true)
         {
+            SnapshotImagePath = snapshotImagePath;
             using var fs = new FileStream(snapshotImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
             using var reader = new BinaryReader(fs);
 
@@ -42,7 +44,7 @@ namespace DiskAccessLibrary
             if (null != BasedImagePath)
             {
                 if (false == File.Exists(BasedImagePath)) throw new FileNotFoundException("based image not found", BasedImagePath);
-                using var ms = File.OpenRead(BasedImagePath);
+                using var ms = new FileStream(BasedImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                 if (snapMatchLength != ms.Length) throw new InvalidDataException("Snapshot size no match to based image");
             }
 

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

@@ -27,20 +27,17 @@ namespace DiskAccessLibrary
         public BlockDifferencingDiskImage(string diskImagePath, bool isReadOnly) : base(diskImagePath, isReadOnly)
         {
             BddInfo = new BddInfo(diskImagePath);
+            IsBlockAllocated = new IReadOnlyIndexer<int, bool>(i => BddInfo.Allocated[i]);
+        }
 
-            if (isReadOnly)
-            {
-                if (null != BddInfo.BasedImagePath) _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
-                _snapshotFileStream = File.OpenRead(Path);
+        public void OpenForRead()
+        {
+            _snapshotFileStream = File.Open(Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+        }
 
-                IsBlockAllocated = new IReadOnlyIndexer<int, bool>(i => BddInfo.Allocated[i]);
-            }
-            else
-            {
-                if (null != BddInfo.BasedImagePath) _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
-                _snapshotFileStream = File.Open(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
-                _isExclusiveLock = true;
-            }
+        public void CloseForRead()
+        {
+            _snapshotFileStream?.Close();
         }
 
         public void ReadBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset)
@@ -199,14 +196,32 @@ namespace DiskAccessLibrary
             _basedFileStream?.Close();
             _snapshotFileStream?.Close();
 
-            _basedFileStream = File.OpenRead(BddInfo.BasedImagePath);
-            _snapshotFileStream = File.Open(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
-
+            if (null != BddInfo.BasedImagePath) _basedFileStream = new FileStream(BddInfo.BasedImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+            _snapshotFileStream = IsReadOnly
+                ? File.Open(Path, FileMode.Open, FileAccess.Read, FileShare.Read)
+                : File.Open(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
             _isExclusiveLock = true;
 
             return true;
         }
 
+        public void Clean()
+        {
+            if (IsReadOnly) return;
+            for (var blockIndex = 0; blockIndex < BddInfo.NumberOfBlocks; blockIndex++)
+            {
+                BddInfo.Allocated[blockIndex] = false;
+            }
+
+            for (var blockIndex = 0; blockIndex < BddInfo.NumberOfBlocks; blockIndex++)
+            {
+                _snapshotFileStream.Position = BddInfo.EntryTableOffset + BddInfo.BlockIndexEntrySize * blockIndex;
+                var bufEntry = BitConverter.GetBytes(BddInfo.Entries[blockIndex]);
+                _snapshotFileStream.Write(bufEntry, 0, bufEntry.Length);
+            }
+            _snapshotFileStream.SetLength(BddInfo.EntryTableOffset + BddInfo.NumberOfBlocks * BddInfo.BlockIndexEntrySize);
+        }
+
         public override bool ReleaseLock()
         {
             _basedFileStream?.Close();
@@ -281,4 +296,4 @@ namespace DiskAccessLibrary
             throw new System.NotImplementedException();
         }
     }
-}
+}

+ 3 - 1
DiskAccessLibrary/Mod/DiskImage.cs

@@ -46,7 +46,9 @@ namespace DiskAccessLibrary
                                 break;
                             }
 
-                            var baseLength = new FileInfo(bdd.BasedImagePath).Length;
+                            long baseLength;
+                            using (var fs = new FileStream(bdd.BasedImagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+                                baseLength = fs.Length;
 
                             info.AppendLine($"Based on:    {bdd.BasedImagePath}");
                             info.AppendLine($"Based Size:  {baseLength / MegaByte:N0} MB");

+ 10 - 8
ISCSI/ISCSI.Server/ISCSITarget.cs

@@ -16,7 +16,8 @@ namespace ISCSI.Server
     public class ISCSITarget : SCSITargetInterface
     {
         private string m_targetName; // ISCSI name
-        private SCSITargetInterface m_target;
+        public SCSITargetInterface Target { get; }
+
         // SCSI events:
         public event EventHandler<StandardInquiryEventArgs> OnStandardInquiry;
         public event EventHandler<UnitSerialNumberInquiryEventArgs> OnUnitSerialNumberInquiry;
@@ -33,20 +34,20 @@ namespace ISCSI.Server
         public ISCSITarget(string targetName, SCSITargetInterface scsiTarget)
         {
             m_targetName = targetName;
-            m_target = scsiTarget;
-            m_target.OnStandardInquiry += new EventHandler<StandardInquiryEventArgs>(Target_OnStandardInquiry);
-            m_target.OnDeviceIdentificationInquiry += new EventHandler<DeviceIdentificationInquiryEventArgs>(Target_OnDeviceIdentificationInquiry);
-            m_target.OnUnitSerialNumberInquiry += new EventHandler<UnitSerialNumberInquiryEventArgs>(Target_OnUnitSerialNumberInquiry);
+            Target = scsiTarget;
+            Target.OnStandardInquiry += new EventHandler<StandardInquiryEventArgs>(Target_OnStandardInquiry);
+            Target.OnDeviceIdentificationInquiry += new EventHandler<DeviceIdentificationInquiryEventArgs>(Target_OnDeviceIdentificationInquiry);
+            Target.OnUnitSerialNumberInquiry += new EventHandler<UnitSerialNumberInquiryEventArgs>(Target_OnUnitSerialNumberInquiry);
         }
 
         public void QueueCommand(byte[] commandBytes, LUNStructure lun, byte[] data, object task, OnCommandCompleted OnCommandCompleted)
         {
-            m_target.QueueCommand(commandBytes, lun, data, task, OnCommandCompleted);
+            Target.QueueCommand(commandBytes, lun, data, task, OnCommandCompleted);
         }
 
         public SCSIStatusCodeName ExecuteCommand(byte[] commandBytes, LUNStructure lun, byte[] data, out byte[] response)
         {
-            return m_target.ExecuteCommand(commandBytes, lun, data, out response);
+            return Target.ExecuteCommand(commandBytes, lun, data, out response);
         }
 
         public void Target_OnStandardInquiry(object sender, StandardInquiryEventArgs args)
@@ -129,8 +130,9 @@ namespace ISCSI.Server
         {
             get
             {
-                return m_target;
+                return Target;
             }
         }
+
     }
 }

+ 10 - 0
ISCSIConsole/MainForm.Designer.cs

@@ -28,6 +28,7 @@ namespace ISCSIConsole
         /// </summary>
         private void InitializeComponent()
         {
+            this.components = new System.ComponentModel.Container();
             this.btnStart = new System.Windows.Forms.Button();
             this.lblPort = new System.Windows.Forms.Label();
             this.txtPort = new System.Windows.Forms.TextBox();
@@ -40,6 +41,7 @@ namespace ISCSIConsole
             this.statusStrip1 = new System.Windows.Forms.StatusStrip();
             this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel();
             this.LoadConfigButton = new System.Windows.Forms.Button();
+            this.MainContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
             this.statusStrip1.SuspendLayout();
             this.SuspendLayout();
             // 
@@ -132,6 +134,7 @@ namespace ISCSIConsole
             this.listTargets.Size = new System.Drawing.Size(265, 88);
             this.listTargets.TabIndex = 9;
             this.listTargets.SelectedIndexChanged += new System.EventHandler(this.listTargets_SelectedIndexChanged);
+            this.listTargets.DoubleClick += new System.EventHandler(this.listTargets_DoubleClick);
             // 
             // statusStrip1
             // 
@@ -159,6 +162,12 @@ namespace ISCSIConsole
             this.LoadConfigButton.UseVisualStyleBackColor = true;
             this.LoadConfigButton.Click += new System.EventHandler(this.LoadConfigButton_Click);
             // 
+            // MainContextMenuStrip
+            // 
+            this.MainContextMenuStrip.Name = "MainContextMenuStrip";
+            this.MainContextMenuStrip.Size = new System.Drawing.Size(181, 26);
+            this.MainContextMenuStrip.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.MainContextMenuStrip_Closed);
+            // 
             // MainForm
             // 
             this.AcceptButton = this.btnStart;
@@ -202,5 +211,6 @@ namespace ISCSIConsole
         private System.Windows.Forms.StatusStrip statusStrip1;
         private System.Windows.Forms.ToolStripStatusLabel lblStatus;
         private System.Windows.Forms.Button LoadConfigButton;
+        private System.Windows.Forms.ContextMenuStrip MainContextMenuStrip;
     }
 }

+ 66 - 15
ISCSIConsole/MainForm.cs

@@ -15,6 +15,8 @@ using System.Net;
 using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.Windows.Forms;
+using DiskAccessLibrary;
+using SCSI;
 using Utilities;
 
 namespace ISCSIConsole
@@ -206,12 +208,6 @@ namespace ISCSIConsole
 
         private void LoadConfigButton_Click(object sender, EventArgs e)
         {
-            if (0 != m_targets.Count)
-            {
-                MessageBox.Show("Remove all targets before load config");
-                return;
-            }
-
             LoadFromConfig();
         }
 
@@ -224,16 +220,10 @@ namespace ISCSIConsole
                 return;
             }
 
-            var arr = new ISCSITarget[entries.Length];
-
-            for (int i = 0; i < arr.Length; i++)
-            {
-                arr[i] = entries[i].CreateTarget();
-            }
-
-            foreach (var target in arr)
+            foreach (var entry in entries)
             {
-                AddTarget(target);
+                if (m_targets.Any(p => p.TargetName == entry.Iqn)) continue;
+                AddTarget(entry.CreateTarget());
             }
         }
 
@@ -244,5 +234,66 @@ namespace ISCSIConsole
             if ("true" == ConfigurationManager.AppSettings["AutoLoadConfig"]) LoadFromConfig();
             if ("true" == ConfigurationManager.AppSettings["AutoStart"]) btnStart_Click(null, null);
         }
+
+        private void listTargets_DoubleClick(object sender, EventArgs e)
+        {
+            if (listTargets.SelectedIndices.Count == 0) return;
+
+            var targetIndex = listTargets.SelectedIndices[0];
+            var target = m_targets[targetIndex];
+
+            if (target.Target is VirtualSCSITarget v)
+            {
+                if (v.Disks.Count == 0)
+                {
+                    MainContextMenuStrip.Items.Add("(no Disks)").Enabled = false;
+                }
+                else
+                {
+                    var dic = new Dictionary<string, ToolStripItem[]>();
+
+                    foreach (var disk in v.Disks)
+                    {
+                        switch (disk)
+                        {
+                            case BlockDifferencingDiskImage bdd:
+                                if (false == bdd.IsNoBaseImage)
+                                {
+                                    var toolStripMenuItem = new ToolStripMenuItem("Clean");
+                                    toolStripMenuItem.Click += (o, args) =>
+                                    {
+                                        var dr = MessageBox.Show($"Are you sure to clean `{bdd.Path}'", "Clean snapshot", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
+                                        if (dr == DialogResult.Yes) bdd.Clean();
+                                    };
+                                    dic[bdd.Path] = new ToolStripItem[] { toolStripMenuItem };
+                                }
+                                break;
+                        }
+                    }
+
+                    if (dic.Count == 0) MainContextMenuStrip.Items.Add("(no option able Disks)").Enabled = false;
+                    else
+                    {
+                        foreach (var item in dic)
+                        {
+                            var m = new ToolStripMenuItem(item.Key);
+                            m.DropDownItems.AddRange(item.Value);
+                            MainContextMenuStrip.Items.Add(m);
+                        }
+                    }
+                }
+                MainContextMenuStrip.Show(MousePosition);
+            }
+            else
+            {
+                MainContextMenuStrip.Items.Add("(non Virtual SCSI Target)").Enabled = false;
+                MainContextMenuStrip.Show(MousePosition);
+            }
+        }
+
+        private void MainContextMenuStrip_Closed(object sender, ToolStripDropDownClosedEventArgs e)
+        {
+            MainContextMenuStrip.Items.Clear();
+        }
     }
 }

+ 3 - 0
ISCSIConsole/MainForm.resx

@@ -120,4 +120,7 @@
   <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
+  <metadata name="MainContextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>138, 17</value>
+  </metadata>
 </root>

+ 2 - 1
ISCSIConsole/Mods/AutoLoadEntry.cs

@@ -85,6 +85,7 @@ namespace ISCSIConsole.Mods
                     var bdd = new BlockDifferencingDiskImage(FilePath, true);
                     try
                     {
+                        bdd.OpenForRead();
                         if (false == bdd.IsNoBaseImage) throw new ConfigurationErrorsException("RamDiskFromFile: Only ** No Base Image Mode ** supported");
 
                         var ramDisk = new UnmanagedGigabyteBlockSeparatedRamDisk((int)Math.Ceiling(bdd.Size / (float)Consts.Gigabyte));
@@ -102,7 +103,7 @@ namespace ISCSIConsole.Mods
                     }
                     finally
                     {
-                        bdd.ReleaseLock();
+                        bdd.CloseForRead();
                     }
 
                 case AutoLoadDiskType.AttachFile:

+ 2 - 2
ISCSIConsole/app.config

@@ -6,8 +6,8 @@
   <appSettings>
     <add key="Listen" value="127.0.0.1" />
     <add key="Port" value="3261" />
-    <add key="AutoLoadConfig" value="true" />
-    <add key="AutoStart" value="true" />
+    <add key="AutoLoadConfig" value="false" />
+    <add key="AutoStart" value="false" />
   </appSettings>
   <autoLoad>
     <entry Enable="false" Iqn="iqn.1991-05.com.talaloni:LocalRamDisk">