Browse Source

Replaced the Command-line interface with a GUI

Tal Aloni 7 years ago
parent
commit
ddae64ba5a
33 changed files with 39930 additions and 1514 deletions
  1. 219 0
      ISCSIConsole/AddTargetForm.Designer.cs
  2. 211 0
      ISCSIConsole/AddTargetForm.cs
  3. 6293 0
      ISCSIConsole/AddTargetForm.resx
  4. 178 0
      ISCSIConsole/CreateDiskImageForm.Designer.cs
  5. 116 0
      ISCSIConsole/CreateDiskImageForm.cs
  6. 6296 0
      ISCSIConsole/CreateDiskImageForm.resx
  7. 74 0
      ISCSIConsole/Helpers/UsageCounter.cs
  8. 78 16
      ISCSIConsole/ISCSIConsole.csproj
  9. BIN
      ISCSIConsole/Icons/SCSI.ico
  10. 191 0
      ISCSIConsole/MainForm.Designer.cs
  11. 201 0
      ISCSIConsole/MainForm.cs
  12. 6296 0
      ISCSIConsole/MainForm.resx
  13. 0 139
      ISCSIConsole/OfflineCommand.cs
  14. 0 278
      ISCSIConsole/Program.AttachCommand.cs
  15. 0 105
      ISCSIConsole/Program.CreateCommand.cs
  16. 0 104
      ISCSIConsole/Program.DetailCommand.cs
  17. 0 71
      ISCSIConsole/Program.HelpCommand.cs
  18. 0 227
      ISCSIConsole/Program.ListCommand.cs
  19. 9 2
      ISCSIConsole/Program.Log.cs
  20. 0 177
      ISCSIConsole/Program.SelectCommand.cs
  21. 0 120
      ISCSIConsole/Program.SetCommand.cs
  22. 0 110
      ISCSIConsole/Program.StartCommand.cs
  23. 44 165
      ISCSIConsole/Program.cs
  24. 139 0
      ISCSIConsole/SelectDiskImageForm.Designer.cs
  25. 73 0
      ISCSIConsole/SelectDiskImageForm.cs
  26. 6296 0
      ISCSIConsole/SelectDiskImageForm.resx
  27. 30 0
      ISCSIConsole/Win32/SecurityHelper.cs
  28. 143 0
      ISCSIConsole/Win32/SelectPhysicalDiskForm.Designer.cs
  29. 153 0
      ISCSIConsole/Win32/SelectPhysicalDiskForm.cs
  30. 6293 0
      ISCSIConsole/Win32/SelectPhysicalDiskForm.resx
  31. 150 0
      ISCSIConsole/Win32/SelectVolumeForm.Designer.cs
  32. 154 0
      ISCSIConsole/Win32/SelectVolumeForm.cs
  33. 6293 0
      ISCSIConsole/Win32/SelectVolumeForm.resx

+ 219 - 0
ISCSIConsole/AddTargetForm.Designer.cs

@@ -0,0 +1,219 @@
+namespace ISCSIConsole
+{
+    partial class AddTargetForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddTargetForm));
+            this.btnAddDiskImage = new System.Windows.Forms.Button();
+            this.btnAddPhysicalDisk = new System.Windows.Forms.Button();
+            this.txtTargetIQN = new System.Windows.Forms.TextBox();
+            this.label1 = new System.Windows.Forms.Label();
+            this.label2 = new System.Windows.Forms.Label();
+            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.btnAddVolume = new System.Windows.Forms.Button();
+            this.btnCreateDiskImage = new System.Windows.Forms.Button();
+            this.btnRemove = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // btnAddDiskImage
+            // 
+            this.btnAddDiskImage.Location = new System.Drawing.Point(340, 73);
+            this.btnAddDiskImage.Name = "btnAddDiskImage";
+            this.btnAddDiskImage.Size = new System.Drawing.Size(140, 23);
+            this.btnAddDiskImage.TabIndex = 4;
+            this.btnAddDiskImage.Text = "Add Existing Virtual Disk";
+            this.btnAddDiskImage.UseVisualStyleBackColor = true;
+            this.btnAddDiskImage.Click += new System.EventHandler(this.btnAddDiskImage_Click);
+            // 
+            // btnAddPhysicalDisk
+            // 
+            this.btnAddPhysicalDisk.Location = new System.Drawing.Point(340, 102);
+            this.btnAddPhysicalDisk.Name = "btnAddPhysicalDisk";
+            this.btnAddPhysicalDisk.Size = new System.Drawing.Size(140, 23);
+            this.btnAddPhysicalDisk.TabIndex = 5;
+            this.btnAddPhysicalDisk.Text = "Add Physical Disk";
+            this.btnAddPhysicalDisk.UseVisualStyleBackColor = true;
+            this.btnAddPhysicalDisk.Visible = false;
+            this.btnAddPhysicalDisk.Click += new System.EventHandler(this.btnAddPhysicalDisk_Click);
+            // 
+            // txtTargetIQN
+            // 
+            this.txtTargetIQN.Location = new System.Drawing.Point(57, 12);
+            this.txtTargetIQN.Name = "txtTargetIQN";
+            this.txtTargetIQN.Size = new System.Drawing.Size(275, 20);
+            this.txtTargetIQN.TabIndex = 1;
+            // 
+            // label1
+            // 
+            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.TabIndex = 4;
+            this.label1.Text = "IQN:";
+            // 
+            // label2
+            // 
+            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.TabIndex = 6;
+            this.label2.Text = "Disks:";
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(324, 200);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 8;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(405, 200);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 9;
+            this.btnCancel.Text = "Cancel";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
+            // 
+            // listDisks
+            // 
+            this.listDisks.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.columnDescription,
+            this.columnSize});
+            this.listDisks.FullRowSelect = true;
+            this.listDisks.Location = new System.Drawing.Point(57, 44);
+            this.listDisks.MultiSelect = false;
+            this.listDisks.Name = "listDisks";
+            this.listDisks.Size = new System.Drawing.Size(275, 139);
+            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);
+            // 
+            // columnDescription
+            // 
+            this.columnDescription.Text = "Description";
+            this.columnDescription.Width = 211;
+            // 
+            // columnSize
+            // 
+            this.columnSize.Text = "Size";
+            // 
+            // btnAddVolume
+            // 
+            this.btnAddVolume.Location = new System.Drawing.Point(340, 131);
+            this.btnAddVolume.Name = "btnAddVolume";
+            this.btnAddVolume.Size = new System.Drawing.Size(140, 23);
+            this.btnAddVolume.TabIndex = 6;
+            this.btnAddVolume.Text = "Add Volume";
+            this.btnAddVolume.UseVisualStyleBackColor = true;
+            this.btnAddVolume.Visible = false;
+            this.btnAddVolume.Click += new System.EventHandler(this.btnAddVolume_Click);
+            // 
+            // btnCreateDiskImage
+            // 
+            this.btnCreateDiskImage.Location = new System.Drawing.Point(340, 44);
+            this.btnCreateDiskImage.Name = "btnCreateDiskImage";
+            this.btnCreateDiskImage.Size = new System.Drawing.Size(140, 23);
+            this.btnCreateDiskImage.TabIndex = 3;
+            this.btnCreateDiskImage.Text = "Create Virtual Disk";
+            this.btnCreateDiskImage.UseVisualStyleBackColor = true;
+            this.btnCreateDiskImage.Click += new System.EventHandler(this.btnCreateDiskImage_Click);
+            // 
+            // btnRemove
+            // 
+            this.btnRemove.Enabled = false;
+            this.btnRemove.Location = new System.Drawing.Point(340, 160);
+            this.btnRemove.Name = "btnRemove";
+            this.btnRemove.Size = new System.Drawing.Size(140, 23);
+            this.btnRemove.TabIndex = 7;
+            this.btnRemove.Text = "Remove";
+            this.btnRemove.UseVisualStyleBackColor = true;
+            this.btnRemove.Click += new System.EventHandler(this.btnRemove_Click);
+            // 
+            // AddTargetForm
+            // 
+            this.AcceptButton = this.btnOK;
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            this.CancelButton = this.btnCancel;
+            this.ClientSize = new System.Drawing.Size(494, 235);
+            this.Controls.Add(this.btnRemove);
+            this.Controls.Add(this.btnCreateDiskImage);
+            this.Controls.Add(this.btnAddVolume);
+            this.Controls.Add(this.listDisks);
+            this.Controls.Add(this.btnCancel);
+            this.Controls.Add(this.btnOK);
+            this.Controls.Add(this.label2);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.txtTargetIQN);
+            this.Controls.Add(this.btnAddPhysicalDisk);
+            this.Controls.Add(this.btnAddDiskImage);
+            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(500, 260);
+            this.MinimumSize = new System.Drawing.Size(500, 260);
+            this.Name = "AddTargetForm";
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+            this.Text = "Add iSCSI Target";
+            this.Load += new System.EventHandler(this.AddTargetForm_Load);
+            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AddTargetForm_FormClosing);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnAddDiskImage;
+        private System.Windows.Forms.Button btnAddPhysicalDisk;
+        private System.Windows.Forms.TextBox txtTargetIQN;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.ListView listDisks;
+        private System.Windows.Forms.ColumnHeader columnDescription;
+        private System.Windows.Forms.ColumnHeader columnSize;
+        private System.Windows.Forms.Button btnAddVolume;
+        private System.Windows.Forms.Button btnCreateDiskImage;
+        private System.Windows.Forms.Button btnRemove;
+    }
+}

+ 211 - 0
ISCSIConsole/AddTargetForm.cs

@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+using DiskAccessLibrary;
+using ISCSI.Server;
+using Utilities;
+
+namespace ISCSIConsole
+{
+    public partial class AddTargetForm : Form
+    {
+        public static int m_targetNumber = 1;
+        public const string DefaultTargetIQN = "iqn.1991-05.com.microsoft";
+
+        private List<Disk> m_disks = new List<Disk>();
+        private ISCSITarget m_target;
+
+        public AddTargetForm()
+        {
+            InitializeComponent();
+#if Win32
+            btnAddPhysicalDisk.Visible = true;
+            btnAddVolume.Visible = true;
+            if (!SecurityHelper.IsAdministrator())
+            {
+                btnAddPhysicalDisk.Enabled = false;
+                btnAddVolume.Enabled = false;
+            }
+#endif
+        }
+
+        private void AddTargetForm_Load(object sender, EventArgs e)
+        {
+            txtTargetIQN.Text = String.Format("{0}:target{1}", DefaultTargetIQN, m_targetNumber);
+        }
+
+        private void btnCreateDiskImage_Click(object sender, EventArgs e)
+        {
+            CreateDiskImageForm createDiskImage = new CreateDiskImageForm();
+            DialogResult result = createDiskImage.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                DiskImage diskImage = createDiskImage.DiskImage;
+                AddDisk(diskImage);
+            }
+        }
+
+        private void btnAddDiskImage_Click(object sender, EventArgs e)
+        {
+            SelectDiskImageForm selectDiskImage = new SelectDiskImageForm();
+            DialogResult result = selectDiskImage.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                DiskImage diskImage = selectDiskImage.DiskImage;
+                AddDisk(diskImage);
+            }
+        }
+
+        private void btnAddPhysicalDisk_Click(object sender, EventArgs e)
+        {
+#if Win32
+            SelectPhysicalDiskForm selectPhysicalDisk = new SelectPhysicalDiskForm();
+            DialogResult result = selectPhysicalDisk.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                AddDisk(selectPhysicalDisk.SelectedDisk);
+            }
+#endif
+        }
+
+        private void btnAddVolume_Click(object sender, EventArgs e)
+        {
+#if Win32
+            SelectVolumeForm selectVolume = new SelectVolumeForm();
+            DialogResult result = selectVolume.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                VolumeDisk volumeDisk = new VolumeDisk(selectVolume.SelectedVolume);
+                if (selectVolume.IsReadOnly)
+                {
+                    volumeDisk.IsReadOnly = true;
+                }
+                AddDisk(volumeDisk);
+            }
+#endif
+        }
+
+        private void AddDisk(Disk disk)
+        {
+            string description = String.Empty;
+            string sizeString = FormattingHelper.GetStandardSizeString(disk.Size);
+            if (disk is DiskImage)
+            {
+                description = ((DiskImage)disk).Path;
+            }
+            else if (disk is PhysicalDisk)
+            {
+                description = String.Format("Physical Disk {0}", ((PhysicalDisk)disk).PhysicalDiskIndex);
+            }
+            else if (disk is VolumeDisk)
+            {
+                description = String.Format("Volume");
+            }
+            ListViewItem item = new ListViewItem(description);
+            item.SubItems.Add(sizeString);
+            listDisks.Items.Add(item);
+            m_disks.Add(disk);
+        }
+
+        private void btnRemove_Click(object sender, EventArgs e)
+        {
+            if (listDisks.SelectedIndices.Count > 0)
+            {
+                int selectedIndex = listDisks.SelectedIndices[0];
+                ReleaseDisk(m_disks[selectedIndex]);
+                m_disks.RemoveAt(selectedIndex);
+                listDisks.Items.RemoveAt(selectedIndex);
+            }
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            if (!ISCSINameHelper.IsValidIQN(txtTargetIQN.Text))
+            {
+                MessageBox.Show("Target IQN is invalid", "Error");
+                return;
+            }
+            m_target = new ISCSITarget(txtTargetIQN.Text, m_disks);
+            m_targetNumber++;
+            this.DialogResult = DialogResult.OK;
+            this.Close();
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = DialogResult.Cancel;
+            this.Close();
+        }
+
+        public ISCSITarget Target
+        {
+            get
+            {
+                return m_target;
+            }
+        }
+
+        private void listDisks_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            btnRemove.Enabled = (listDisks.SelectedIndices.Count > 0);
+        }
+
+        private void listDisks_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
+        {
+            e.NewWidth = ((ListView)sender).Columns[e.ColumnIndex].Width;
+            e.Cancel = true;
+        }
+
+        private void AddTargetForm_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            if (this.DialogResult != DialogResult.OK)
+            {
+                ReleaseDisks(m_disks);
+            }
+        }
+
+        public static void ReleaseDisks(List<Disk> disks)
+        {
+            foreach (Disk disk in disks)
+            {
+                ReleaseDisk(disk);
+            }
+        }
+
+        private static void ReleaseDisk(Disk disk)
+        {
+            if (disk is DiskImage)
+            {
+                ((DiskImage)disk).ReleaseLock();
+            }
+#if Win32
+            else if (disk is PhysicalDisk)
+            {
+                if (!DiskAccessLibrary.LogicalDiskManager.DynamicDisk.IsDynamicDisk(disk))
+                {
+                    LockHelper.UnlockBasicDiskAndVolumes((PhysicalDisk)disk);
+                    try
+                    {
+                        ((PhysicalDisk)disk).UpdateProperties();
+                    }
+                    catch (System.IO.IOException)
+                    {
+                    }
+                }
+            }
+            else if (disk is VolumeDisk)
+            {
+                Guid? windowsVolumeGuid = WindowsVolumeHelper.GetWindowsVolumeGuid(((VolumeDisk)disk).Volume);
+                if (windowsVolumeGuid.HasValue)
+                {
+                    WindowsVolumeManager.ReleaseLock(windowsVolumeGuid.Value);
+                }
+            }
+#endif
+        }
+    }
+}

File diff suppressed because it is too large
+ 6293 - 0
ISCSIConsole/AddTargetForm.resx


+ 178 - 0
ISCSIConsole/CreateDiskImageForm.Designer.cs

@@ -0,0 +1,178 @@
+namespace ISCSIConsole
+{
+    partial class CreateDiskImageForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        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.lblSize = new System.Windows.Forms.Label();
+            this.label1 = 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.btnOK = new System.Windows.Forms.Button();
+            this.btnCancel = new System.Windows.Forms.Button();
+            ((System.ComponentModel.ISupportInitialize)(this.numericDiskSize)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // saveVirtualDiskFileDialog
+            // 
+            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[] {
+            100000000,
+            0,
+            0,
+            0});
+            this.numericDiskSize.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,
+            0,
+            0,
+            0});
+            // 
+            // lblSize
+            // 
+            this.lblSize.AutoSize = true;
+            this.lblSize.Location = new System.Drawing.Point(12, 43);
+            this.lblSize.Name = "lblSize";
+            this.lblSize.Size = new System.Drawing.Size(30, 13);
+            this.lblSize.TabIndex = 1;
+            this.lblSize.Text = "Size:";
+            // 
+            // label1
+            // 
+            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";
+            // 
+            // lblFilePath
+            // 
+            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.TabIndex = 3;
+            this.lblFilePath.Text = "File:";
+            // 
+            // txtFilePath
+            // 
+            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;
+            // 
+            // btnBrowse
+            // 
+            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);
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(224, 88);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 6;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(305, 88);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 7;
+            this.btnCancel.Text = "Cancel";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
+            // 
+            // 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.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.Controls.Add(this.label1);
+            this.Controls.Add(this.lblSize);
+            this.Controls.Add(this.numericDiskSize);
+            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.Name = "CreateDiskImageForm";
+            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.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.SaveFileDialog saveVirtualDiskFileDialog;
+        private System.Windows.Forms.NumericUpDown numericDiskSize;
+        private System.Windows.Forms.Label lblSize;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label lblFilePath;
+        private System.Windows.Forms.TextBox txtFilePath;
+        private System.Windows.Forms.Button btnBrowse;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.Button btnCancel;
+    }
+}

+ 116 - 0
ISCSIConsole/CreateDiskImageForm.cs

@@ -0,0 +1,116 @@
+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;
+
+namespace ISCSIConsole
+{
+    public partial class CreateDiskImageForm : Form
+    {
+        private DiskImage m_diskImage;
+        private bool m_isWorking = false;
+
+        public CreateDiskImageForm()
+        {
+            InitializeComponent();
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = DialogResult.Cancel;
+            this.Close();
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            string path = txtFilePath.Text;
+            long size = (long)numericDiskSize.Value * 1024 * 1024;
+            if (path == String.Empty)
+            {
+                MessageBox.Show("Please choose file location", "Error");
+                return;
+            }
+            m_isWorking = true;
+            new Thread(delegate()
+            {
+                DiskImage diskImage;
+                try
+                {
+                    diskImage = VirtualHardDisk.Create(path, size);
+                }
+                catch (IOException ex)
+                {
+                    this.Invoke((MethodInvoker)delegate()
+                    {
+                        MessageBox.Show("Failed to create the disk: " + ex.Message, "Error");
+                        txtFilePath.Enabled = true;
+                        btnBrowse.Enabled = true;
+                        numericDiskSize.Enabled = true;
+                        btnOK.Enabled = true;
+                        btnCancel.Enabled = true;
+                    });
+                    m_isWorking = false;
+                    return;
+                }
+                bool isLocked = diskImage.ExclusiveLock();
+                if (!isLocked)
+                {
+                    this.Invoke((MethodInvoker)delegate()
+                    {
+                        MessageBox.Show("Cannot lock the disk image for exclusive access", "Error");
+                        txtFilePath.Enabled = true;
+                        btnBrowse.Enabled = true;
+                        numericDiskSize.Enabled = true;
+                        btnOK.Enabled = true;
+                        btnCancel.Enabled = true;
+                    });
+                    m_isWorking = false;
+                    return;
+                }
+                m_diskImage = diskImage;
+                m_isWorking = false;
+                this.Invoke((MethodInvoker)delegate()
+                {
+                    this.DialogResult = DialogResult.OK;
+                    this.Close();
+                });
+            }).Start();
+            txtFilePath.Enabled = false;
+            btnBrowse.Enabled = false;
+            numericDiskSize.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
+        {
+            get
+            {
+                return m_diskImage;
+            }
+        }
+
+        private void CreateDiskImageForm_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            if (m_isWorking)
+            {
+                e.Cancel = true;
+                MessageBox.Show("Please wait until the creation of the disk image is completed.", "Error");
+            }
+        }
+    }
+}

File diff suppressed because it is too large
+ 6296 - 0
ISCSIConsole/CreateDiskImageForm.resx


+ 74 - 0
ISCSIConsole/Helpers/UsageCounter.cs

@@ -0,0 +1,74 @@
+/* Copyright (C) 2016 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.Text;
+using System.Threading;
+
+namespace ISCSIConsole
+{
+    public class UsageCounter
+    {
+        private SortedList<string, int> m_targetsInUse = new SortedList<string, int>();
+        private int m_sessionCount = 0;
+
+        public void NotifySessionStart(string targetName)
+        {
+            Interlocked.Increment(ref m_sessionCount);
+            lock (m_targetsInUse)
+            {
+                int index = m_targetsInUse.IndexOfKey(targetName);
+                if (index >= 0)
+                {
+                    m_targetsInUse[targetName]++;
+                }
+                else
+                {
+                    m_targetsInUse.Add(targetName, 1);
+                }
+            }
+        }
+
+        public void NotifySessionTermination(string targetName)
+        {
+            Interlocked.Decrement(ref m_sessionCount);
+            lock (m_targetsInUse)
+            {
+                int index = m_targetsInUse.IndexOfKey(targetName);
+                if (index >= 0)
+                {
+                    int useCount = m_targetsInUse[targetName];
+                    useCount--;
+                    if (useCount == 0)
+                    {
+                        m_targetsInUse.Remove(targetName);
+                    }
+                    else
+                    {
+                        m_targetsInUse[targetName] = useCount;
+                    }
+                }
+            }
+        }
+
+        public bool IsTargetInUse(string targetName)
+        {
+            lock (m_targetsInUse)
+            {
+                return m_targetsInUse.ContainsKey(targetName);
+            }
+        }
+
+        public int SessionCount
+        {
+            get
+            {
+                return m_sessionCount;
+            }
+        }
+    }
+}

+ 78 - 16
ISCSIConsole/ISCSIConsole.csproj

@@ -5,17 +5,18 @@
     <ProductVersion>8.0.50727</ProductVersion>
     <ProductVersion>8.0.50727</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{6C9727E4-00AC-4DE0-86A3-5A10259DE3E4}</ProjectGuid>
     <ProjectGuid>{6C9727E4-00AC-4DE0-86A3-5A10259DE3E4}</ProjectGuid>
-    <OutputType>Exe</OutputType>
+    <OutputType>WinExe</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>ISCSIConsole</RootNamespace>
     <RootNamespace>ISCSIConsole</RootNamespace>
     <AssemblyName>ISCSIConsole</AssemblyName>
     <AssemblyName>ISCSIConsole</AssemblyName>
+    <ApplicationIcon>Icons\SCSI.ico</ApplicationIcon>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   </PropertyGroup>
@@ -23,30 +24,94 @@
     <DebugType>pdbonly</DebugType>
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
     <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
+    <DefineConstants>TRACE;Win32</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System" />
-    <Reference Include="System.ServiceProcess" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <Compile Include="AddTargetForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="AddTargetForm.Designer.cs">
+      <DependentUpon>AddTargetForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="CreateDiskImageForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="CreateDiskImageForm.Designer.cs">
+      <DependentUpon>CreateDiskImageForm.cs</DependentUpon>
+    </Compile>
     <Compile Include="Disks\VolumeDisk.cs" />
     <Compile Include="Disks\VolumeDisk.cs" />
     <Compile Include="Helpers\FormattingHelper.cs" />
     <Compile Include="Helpers\FormattingHelper.cs" />
     <Compile Include="Helpers\ISCSINameHelper.cs" />
     <Compile Include="Helpers\ISCSINameHelper.cs" />
-    <Compile Include="OfflineCommand.cs" />
-    <Compile Include="Program.AttachCommand.cs" />
-    <Compile Include="Program.CreateCommand.cs" />
+    <Compile Include="Helpers\UsageCounter.cs" />
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Program.cs" />
-    <Compile Include="Program.DetailCommand.cs" />
-    <Compile Include="Program.HelpCommand.cs" />
-    <Compile Include="Program.ListCommand.cs" />
     <Compile Include="Program.Log.cs" />
     <Compile Include="Program.Log.cs" />
-    <Compile Include="Program.SelectCommand.cs" />
-    <Compile Include="Program.SetCommand.cs" />
-    <Compile Include="Program.StartCommand.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SelectDiskImageForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="SelectDiskImageForm.Designer.cs">
+      <DependentUpon>SelectDiskImageForm.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="AddTargetForm.resx">
+      <SubType>Designer</SubType>
+      <DependentUpon>AddTargetForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="CreateDiskImageForm.resx">
+      <SubType>Designer</SubType>
+      <DependentUpon>CreateDiskImageForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="MainForm.resx">
+      <SubType>Designer</SubType>
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="SelectDiskImageForm.resx">
+      <DependentUpon>SelectDiskImageForm.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Win32\SecurityHelper.cs" />
+    <Compile Include="Win32\SelectPhysicalDiskForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Win32\SelectPhysicalDiskForm.Designer.cs">
+      <DependentUpon>SelectPhysicalDiskForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Win32\SelectVolumeForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Win32\SelectVolumeForm.Designer.cs">
+      <DependentUpon>SelectVolumeForm.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Win32\SelectPhysicalDiskForm.resx">
+      <DependentUpon>SelectPhysicalDiskForm.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Win32\SelectVolumeForm.resx">
+      <DependentUpon>SelectVolumeForm.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Icons\SCSI.ico" />
+    <Content Include="RevisionHistory.txt" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\DiskAccessLibrary\DiskAccessLibrary.csproj">
     <ProjectReference Include="..\DiskAccessLibrary\DiskAccessLibrary.csproj">
@@ -62,9 +127,6 @@
       <Name>Utilities</Name>
       <Name>Utilities</Name>
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>
-  <ItemGroup>
-    <Content Include="RevisionHistory.txt" />
-  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.

BIN
ISCSIConsole/Icons/SCSI.ico


+ 191 - 0
ISCSIConsole/MainForm.Designer.cs

@@ -0,0 +1,191 @@
+namespace ISCSIConsole
+{
+    partial class MainForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
+            this.btnStart = new System.Windows.Forms.Button();
+            this.lblPort = new System.Windows.Forms.Label();
+            this.txtPort = new System.Windows.Forms.TextBox();
+            this.lblIPAddress = new System.Windows.Forms.Label();
+            this.comboIPAddress = new System.Windows.Forms.ComboBox();
+            this.btnAddTarget = new System.Windows.Forms.Button();
+            this.lblTargets = new System.Windows.Forms.Label();
+            this.btnRemoveTarget = new System.Windows.Forms.Button();
+            this.listTargets = new System.Windows.Forms.ListBox();
+            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
+            this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel();
+            this.statusStrip1.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // btnStart
+            // 
+            this.btnStart.Location = new System.Drawing.Point(354, 12);
+            this.btnStart.Name = "btnStart";
+            this.btnStart.Size = new System.Drawing.Size(106, 23);
+            this.btnStart.TabIndex = 0;
+            this.btnStart.Text = "Start";
+            this.btnStart.UseVisualStyleBackColor = true;
+            this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
+            // 
+            // lblPort
+            // 
+            this.lblPort.AutoSize = true;
+            this.lblPort.Location = new System.Drawing.Point(232, 17);
+            this.lblPort.Name = "lblPort";
+            this.lblPort.Size = new System.Drawing.Size(53, 13);
+            this.lblPort.TabIndex = 1;
+            this.lblPort.Text = "TCP Port:";
+            // 
+            // txtPort
+            // 
+            this.txtPort.Location = new System.Drawing.Point(291, 14);
+            this.txtPort.Name = "txtPort";
+            this.txtPort.Size = new System.Drawing.Size(53, 20);
+            this.txtPort.TabIndex = 2;
+            this.txtPort.Text = "3260";
+            // 
+            // lblIPAddress
+            // 
+            this.lblIPAddress.AutoSize = true;
+            this.lblIPAddress.Location = new System.Drawing.Point(12, 16);
+            this.lblIPAddress.Name = "lblIPAddress";
+            this.lblIPAddress.Size = new System.Drawing.Size(61, 13);
+            this.lblIPAddress.TabIndex = 3;
+            this.lblIPAddress.Text = "IP Address:";
+            // 
+            // comboIPAddress
+            // 
+            this.comboIPAddress.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.comboIPAddress.FormattingEnabled = true;
+            this.comboIPAddress.Location = new System.Drawing.Point(79, 13);
+            this.comboIPAddress.Name = "comboIPAddress";
+            this.comboIPAddress.Size = new System.Drawing.Size(136, 21);
+            this.comboIPAddress.TabIndex = 4;
+            // 
+            // btnAddTarget
+            // 
+            this.btnAddTarget.Location = new System.Drawing.Point(354, 57);
+            this.btnAddTarget.Name = "btnAddTarget";
+            this.btnAddTarget.Size = new System.Drawing.Size(106, 23);
+            this.btnAddTarget.TabIndex = 5;
+            this.btnAddTarget.Text = "Add Target";
+            this.btnAddTarget.UseVisualStyleBackColor = true;
+            this.btnAddTarget.Click += new System.EventHandler(this.btnAddTarget_Click);
+            // 
+            // lblTargets
+            // 
+            this.lblTargets.AutoSize = true;
+            this.lblTargets.Location = new System.Drawing.Point(12, 57);
+            this.lblTargets.Name = "lblTargets";
+            this.lblTargets.Size = new System.Drawing.Size(46, 13);
+            this.lblTargets.TabIndex = 7;
+            this.lblTargets.Text = "Targets:";
+            // 
+            // btnRemoveTarget
+            // 
+            this.btnRemoveTarget.Enabled = false;
+            this.btnRemoveTarget.Location = new System.Drawing.Point(354, 86);
+            this.btnRemoveTarget.Name = "btnRemoveTarget";
+            this.btnRemoveTarget.Size = new System.Drawing.Size(106, 23);
+            this.btnRemoveTarget.TabIndex = 8;
+            this.btnRemoveTarget.Text = "Remove Target";
+            this.btnRemoveTarget.UseVisualStyleBackColor = true;
+            this.btnRemoveTarget.Click += new System.EventHandler(this.btnRemoveTarget_Click);
+            // 
+            // listTargets
+            // 
+            this.listTargets.FormattingEnabled = true;
+            this.listTargets.Location = new System.Drawing.Point(79, 57);
+            this.listTargets.Name = "listTargets";
+            this.listTargets.Size = new System.Drawing.Size(265, 95);
+            this.listTargets.TabIndex = 9;
+            this.listTargets.SelectedIndexChanged += new System.EventHandler(this.listTargets_SelectedIndexChanged);
+            // 
+            // statusStrip1
+            // 
+            this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.lblStatus});
+            this.statusStrip1.Location = new System.Drawing.Point(0, 173);
+            this.statusStrip1.Name = "statusStrip1";
+            this.statusStrip1.Size = new System.Drawing.Size(474, 22);
+            this.statusStrip1.SizingGrip = false;
+            this.statusStrip1.TabIndex = 10;
+            this.statusStrip1.Text = "statusStrip1";
+            // 
+            // lblActiveSessions
+            // 
+            this.lblStatus.Name = "lblActiveSessions";
+            this.lblStatus.Size = new System.Drawing.Size(0, 17);
+            // 
+            // MainForm
+            // 
+            this.AcceptButton = this.btnStart;
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            this.ClientSize = new System.Drawing.Size(474, 195);
+            this.Controls.Add(this.statusStrip1);
+            this.Controls.Add(this.listTargets);
+            this.Controls.Add(this.btnRemoveTarget);
+            this.Controls.Add(this.lblTargets);
+            this.Controls.Add(this.btnAddTarget);
+            this.Controls.Add(this.comboIPAddress);
+            this.Controls.Add(this.lblIPAddress);
+            this.Controls.Add(this.txtPort);
+            this.Controls.Add(this.lblPort);
+            this.Controls.Add(this.btnStart);
+            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(480, 220);
+            this.MinimumSize = new System.Drawing.Size(480, 220);
+            this.Name = "MainForm";
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+            this.Text = "iSCSI Console";
+            this.Load += new System.EventHandler(this.MainForm_Load);
+            this.statusStrip1.ResumeLayout(false);
+            this.statusStrip1.PerformLayout();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnStart;
+        private System.Windows.Forms.Label lblPort;
+        private System.Windows.Forms.TextBox txtPort;
+        private System.Windows.Forms.Label lblIPAddress;
+        private System.Windows.Forms.ComboBox comboIPAddress;
+        private System.Windows.Forms.Button btnAddTarget;
+        private System.Windows.Forms.Label lblTargets;
+        private System.Windows.Forms.Button btnRemoveTarget;
+        private System.Windows.Forms.ListBox listTargets;
+        private System.Windows.Forms.StatusStrip statusStrip1;
+        private System.Windows.Forms.ToolStripStatusLabel lblStatus;
+    }
+}

+ 201 - 0
ISCSIConsole/MainForm.cs

@@ -0,0 +1,201 @@
+/* Copyright (C) 2016 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.ComponentModel;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+using ISCSI.Server;
+using DiskAccessLibrary;
+using Utilities;
+
+namespace ISCSIConsole
+{
+    public partial class MainForm : Form
+    {
+        private ISCSIServer m_server = new ISCSIServer();
+        private List<ISCSITarget> m_targets = new List<ISCSITarget>();
+        private UsageCounter m_usageCounter = new UsageCounter();
+        private bool m_started = false;
+
+        public MainForm()
+        {
+            InitializeComponent();
+        }
+
+        private void MainForm_Load(object sender, EventArgs e)
+        {
+            this.Text += " v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
+            m_server.OnLogEntry += Program.OnLogEntry;
+
+            List<IPAddress> localIPs = GetHostIPAddresses();
+            KeyValuePairList<string, IPAddress> list = new KeyValuePairList<string, IPAddress>();
+            list.Add("Any", IPAddress.Any);
+            foreach (IPAddress address in localIPs)
+            {
+                list.Add(address.ToString(), address);
+            }
+            comboIPAddress.DataSource = list;
+            comboIPAddress.DisplayMember = "Key";
+            comboIPAddress.ValueMember = "Value";
+#if Win32
+            if (!SecurityHelper.IsAdministrator())
+            {
+                lblStatus.Text = "Some features require administrator privileges and have been disabled";
+            }
+#endif
+        }
+
+        private void btnStart_Click(object sender, EventArgs e)
+        {
+            if (!m_started)
+            {
+                IPAddress serverAddress = (IPAddress)comboIPAddress.SelectedValue;
+                int port = Conversion.ToInt32(txtPort.Text, 0);
+                if (port <= 0 || port > UInt16.MaxValue)
+                {
+                    MessageBox.Show("Invalid TCP port", "Error");
+                    return;
+                }
+                IPEndPoint endpoint = new IPEndPoint(serverAddress, port);
+                try
+                {
+                    m_server.Start(endpoint);
+                }
+                catch (SocketException ex)
+                {
+                    MessageBox.Show("Cannot start server, " + ex.Message, "Error");
+                    return;
+                }
+                btnStart.Text = "Stop";
+                txtPort.Enabled = false;
+                comboIPAddress.Enabled = false;
+                m_started = true;
+                UpdateUI();
+            }
+            else
+            {
+                m_server.Stop();
+                lblStatus.Text = String.Empty;
+                m_started = false;
+                btnStart.Text = "Start";
+                txtPort.Enabled = true;
+                comboIPAddress.Enabled = true;
+            }
+        }
+
+        private void btnAddTarget_Click(object sender, EventArgs e)
+        {
+            AddTargetForm addTarget = new AddTargetForm();
+            DialogResult addTargetResult = addTarget.ShowDialog();
+            if (addTargetResult == DialogResult.OK)
+            {
+                ISCSITarget target = addTarget.Target;
+                ((SCSI.VirtualSCSITarget)target.SCSITarget).OnLogEntry += Program.OnLogEntry;
+                target.OnAuthorizationRequest += new EventHandler<AuthorizationRequestArgs>(ISCSITarget_OnAuthorizationRequest);
+                target.OnSessionTermination += new EventHandler<SessionTerminationArgs>(ISCSITarget_OnSessionTermination);
+                m_targets.Add(target);
+                try
+                {
+                    m_server.AddTarget(target);
+                }
+                catch (ArgumentException ex)
+                {
+                    MessageBox.Show(ex.Message, "Error");
+                    return;
+                }
+                listTargets.Items.Add(target.TargetName);
+            }
+        }
+
+        private void btnRemoveTarget_Click(object sender, EventArgs e)
+        {
+            if (listTargets.SelectedIndices.Count > 0)
+            {
+                int targetIndex = listTargets.SelectedIndices[0];
+                ISCSITarget target = m_targets[targetIndex];
+                bool isTargetRemoved = m_server.RemoveTarget(target.TargetName);
+                if (!isTargetRemoved)
+                {
+                    MessageBox.Show("Could not remove iSCSI target", "Error");
+                    return;
+                }
+                List<Disk> disks = ((SCSI.VirtualSCSITarget)target.SCSITarget).Disks;
+                AddTargetForm.ReleaseDisks(disks);
+                m_targets.RemoveAt(targetIndex);
+                listTargets.Items.RemoveAt(targetIndex);
+            }
+        }
+
+        private void ISCSITarget_OnAuthorizationRequest(object sender, AuthorizationRequestArgs e)
+        {
+            string targetName = ((ISCSITarget)sender).TargetName;
+            m_usageCounter.NotifySessionStart(targetName);
+            UpdateUI();
+        }
+
+        private void ISCSITarget_OnSessionTermination(object sender, SessionTerminationArgs e)
+        {
+            string targetName = ((ISCSITarget)sender).TargetName;
+            m_usageCounter.NotifySessionTermination(targetName);
+            UpdateUI();
+        }
+
+        private void UpdateUI()
+        {
+            if (this.InvokeRequired)
+            {
+                this.Invoke((MethodInvoker)UpdateUI);
+            }
+            else
+            {
+                if (m_started)
+                {
+                    lblStatus.Text = String.Format("{0} Active Sessions", m_usageCounter.SessionCount);
+                }
+
+                if (listTargets.SelectedIndices.Count > 0)
+                {
+                    int targetIndex = listTargets.SelectedIndices[0];
+                    ISCSITarget target = m_targets[targetIndex];
+                    bool isInUse = m_usageCounter.IsTargetInUse(target.TargetName);
+                    btnRemoveTarget.Enabled = !isInUse;
+                }
+                else
+                {
+                    btnRemoveTarget.Enabled = false;
+                }
+            }
+        }
+
+        private static List<IPAddress> GetHostIPAddresses()
+        {
+            List<IPAddress> result = new List<IPAddress>();
+            foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
+            {
+                IPInterfaceProperties ipProperties = netInterface.GetIPProperties();
+                foreach (UnicastIPAddressInformation addressInfo in ipProperties.UnicastAddresses)
+                {
+                    if (addressInfo.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+                    {
+                        result.Add(addressInfo.Address);
+                    }
+                }
+            }
+            return result;
+        }
+
+        private void listTargets_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            UpdateUI();
+        }
+    }
+}

File diff suppressed because it is too large
+ 6296 - 0
ISCSIConsole/MainForm.resx


+ 0 - 139
ISCSIConsole/OfflineCommand.cs

@@ -1,139 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using DiskAccessLibrary;
-using DiskAccessLibrary.LogicalDiskManager;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        public static void OfflineCommand(string[] args)
-        {
-            if (args.Length > 1)
-            {
-                switch (args[1].ToLower())
-                {
-                    case "disk":
-                        {
-                            if (m_selectedDisk != null)
-                            {
-                                if (m_selectedDisk is PhysicalDisk)
-                                {
-                                    if (Environment.OSVersion.Version.Major >= 6)
-                                    {
-                                        bool isOnline = ((PhysicalDisk)m_selectedDisk).GetOnlineStatus();
-                                        if (isOnline)
-                                        {
-                                            bool success = ((PhysicalDisk)m_selectedDisk).SetOnlineStatus(false, true);
-                                            if (success)
-                                            {
-                                                Console.WriteLine("Disk has been taken offline.");
-                                            }
-                                            else
-                                            {
-                                                Console.WriteLine("Failed to take the disk offline.");
-                                            }
-                                        }
-                                        else
-                                        {
-                                            Console.WriteLine("Disk is already offline.");
-                                        }
-                                    }
-                                    else
-                                    {
-                                        Console.WriteLine("This command is only supported on Windows Vista and later.");
-                                    }
-                                }
-                            }
-                            else
-                            {
-                                Console.WriteLine("No disk has been selected.");
-                            }
-                            break;
-                        }
-                    default:
-                        {
-                            Console.WriteLine("Invalid argument.");
-                            break;
-                        }
-                }
-            }
-            else
-            {
-                Console.WriteLine("Invalid argument.");
-            }
-        }
-
-        public static void OnlineCommand(string[] args)
-        {
-            if (args.Length > 1)
-            {
-                switch (args[1].ToLower())
-                {
-                    case "disk":
-                        {
-                            if (m_selectedDisk != null)
-                            {
-                                if (m_selectedDisk is PhysicalDisk)
-                                {
-                                    if (Environment.OSVersion.Version.Major >= 6)
-                                    {
-                                        bool isOnline = ((PhysicalDisk)m_selectedDisk).GetOnlineStatus();
-                                        if (!isOnline)
-                                        {
-                                            bool success = ((PhysicalDisk)m_selectedDisk).SetOnlineStatus(true, true);
-                                            if (success)
-                                            {
-                                                Console.WriteLine("Disk has been taken online.");
-                                            }
-                                            else
-                                            {
-                                                Console.WriteLine("Failed to take the disk online.");
-                                            }
-                                        }
-                                        else
-                                        {
-                                            Console.WriteLine("Disk is already online.");
-                                        }
-                                    }
-                                    else
-                                    {
-                                        Console.WriteLine("This command is only supported on Windows Vista and later.");
-                                    }
-                                }
-                            }
-                            else
-                            {
-                                Console.WriteLine("No disk has been selected.");
-                            }
-                            break;
-                        }
-                    default:
-                        {
-                            Console.WriteLine("Invalid argument.");
-                            break;
-                        }
-                }
-            }
-            else
-            {
-                Console.WriteLine("Invalid argument.");
-            }
-        }
-
-        public static void HelpOffline()
-        {
-            Console.WriteLine();
-            Console.WriteLine("OFFLINE DISK - Takes the selected disk offline.");
-        }
-
-        public static void HelpOnline()
-        {
-            Console.WriteLine();
-            Console.WriteLine("ONLINE DISK - Takes the selected disk online.");
-        }
-    }
-}

+ 0 - 278
ISCSIConsole/Program.AttachCommand.cs

@@ -1,278 +0,0 @@
-/* Copyright (C) 2012-2016 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 DiskAccessLibrary;
-using DiskAccessLibrary.LogicalDiskManager;
-using SCSI;
-using ISCSI.Server;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    partial class Program
-    {
-        public const string DefaultTargetIQN = "iqn.1991-05.com.microsoft";
-
-        public static void AttachCommand(string[] args)
-        {
-            if (m_server != null)
-            {
-                Console.WriteLine("Server is already running");
-                return;
-            }
-
-            if (args.Length >= 2)
-            {
-                KeyValuePairList<string, string> parameters = ParseParameters(args, 2);
-                if (!VerifyParameters(parameters, "vdisk", "disk", "volume", "readonly", "target"))
-                {
-                    Console.WriteLine();
-                    Console.WriteLine("Invalid parameter");
-                    HelpAttach();
-                    return;
-                }
-
-                switch (args[1].ToLower())
-                {
-                    case "vdisk":
-                        {
-                            if (m_selectedDisk == null)
-                            {
-                                Console.WriteLine("No disk has been selected");
-                                break;
-                            }
-
-                            if (!(m_selectedDisk is DiskImage))
-                            {
-                                Console.WriteLine("Selected disk is not a disk image");
-                                break;
-                            }
-
-                            DiskImage disk = (DiskImage)m_selectedDisk;
-                            string defaultStorageTargetName = Path.GetFileNameWithoutExtension(disk.Path);
-                            string defaultTargetName = DefaultTargetIQN + ":" + defaultStorageTargetName.Replace(" ", ""); // spaces are not allowed
-                            AttachISCSIDisk(disk, defaultTargetName, parameters);
-                            break;
-                        }
-                    case "disk":
-                        {
-                            if (m_selectedDisk == null)
-                            {
-                                Console.WriteLine("Error: No disk has been selected.");
-                                break;
-                            }
-
-                            if (!(m_selectedDisk is PhysicalDisk))
-                            {
-                                Console.WriteLine("Error: The selected disk is not a physical disk.");
-                                break;
-                            }
-
-                            bool isAttachmentReadOnly = parameters.ContainsKey("readonly");
-                            PhysicalDisk disk = (PhysicalDisk)m_selectedDisk;
-                            if (!isAttachmentReadOnly)
-                            {
-                                if (Environment.OSVersion.Version.Major >= 6)
-                                {
-                                    bool isDiskReadOnly;
-                                    bool isOnline = disk.GetOnlineStatus(out isDiskReadOnly);
-                                    if (isOnline)
-                                    {
-                                        Console.WriteLine();
-                                        Console.WriteLine("Error: The selected disk must be taken offline.");
-                                        break;
-                                    }
-
-                                    if (!isAttachmentReadOnly && isDiskReadOnly)
-                                    {
-                                        Console.WriteLine();
-                                        Console.WriteLine("Error: The selected disk is set to readonly!");
-                                        break;
-                                    }
-                                }
-                                else
-                                {
-                                    Console.WriteLine();
-                                    // Locking mechanism is not implemented
-                                    Console.Write("Warning: if a volume on this disk is mounted locally, data corruption may occur!");
-                                }
-                            }
-                            string defaultStorageTargetName = string.Format("disk{0}", disk.PhysicalDiskIndex);
-                            string defaultTargetName = DefaultTargetIQN + ":" + defaultStorageTargetName;
-                            AttachISCSIDisk(disk, defaultTargetName, parameters);
-                            break;
-                        }
-                    case "volume":
-                        {
-                            if (m_selectedVolume == null)
-                            {
-                                Console.WriteLine("No volume has been selected.");
-                                break;
-                            }
-
-                            VolumeDisk virtualDisk = new VolumeDisk(m_selectedVolume);
-                            string defaultTargetName = DefaultTargetIQN + ":Volume";
-                            bool isAttachmentReadOnly = parameters.ContainsKey("readonly");
-                            if (!isAttachmentReadOnly)
-                            {
-                                if (Environment.OSVersion.Version.Major >= 6)
-                                {
-                                    if (m_selectedVolume is DynamicVolume)
-                                    {
-                                        foreach(DiskExtent extent in ((DynamicVolume)m_selectedVolume).Extents)
-                                        {
-                                            if (extent.Disk is PhysicalDisk)
-                                            {
-                                                bool isDiskReadOnly;
-                                                bool isOnline = ((PhysicalDisk)extent.Disk).GetOnlineStatus(out isDiskReadOnly);
-                                                if (isOnline)
-                                                {
-                                                    Console.WriteLine("Error: All disks containing the volume must be taken offline.");
-                                                    return;
-                                                }
-
-                                                if (isDiskReadOnly)
-                                                {
-                                                    Console.WriteLine("Error: A disk containing the volume is set to readonly.");
-                                                    return;
-                                                }
-                                            }
-                                        }
-                                    }
-                                    else if (m_selectedVolume is Partition)
-                                    {
-                                        Disk disk = ((Partition)m_selectedVolume).Disk;
-                                        if (disk is PhysicalDisk)
-                                        {
-                                            bool isDiskReadOnly;
-                                            bool isOnline = ((PhysicalDisk)disk).GetOnlineStatus(out isDiskReadOnly);
-
-                                            if (isOnline)
-                                            {
-                                                Console.WriteLine("Error: The disk containing the volume must be taken offline.");
-                                                return;
-                                            }
-
-                                            if (isDiskReadOnly)
-                                            {
-                                                Console.WriteLine("Error: The disk containing the volume is set to readonly.");
-                                                return;
-                                            }
-                                        }
-                                    }
-                                }
-                                else
-                                {
-                                    Console.WriteLine();
-                                    // Locking mechanism is not implemented
-                                    Console.WriteLine("Warning: if this volume is mounted locally, data corruption may occur!");
-                                }
-                            }
-                            AttachISCSIDisk(virtualDisk, defaultTargetName, parameters);
-                            break;
-                        }
-                    default:
-                        {
-                            Console.WriteLine();
-                            Console.WriteLine("Invalid argument.");
-                            HelpAttach();
-                            break;
-                        }
-                }
-            }
-            else
-            {
-                HelpAttach();
-            }
-        }
-
-        public static void HelpAttach()
-        {
-            Console.WriteLine();
-            Console.WriteLine("ATTACH VDISK [READONLY] [TARGET=<NAME>]  - Attach virtual hard disk file");
-            Console.WriteLine("ATTACH DISK [READONLY] [TARGET=<NAME>]   - Attach selected physical disk");
-            Console.WriteLine("ATTACH VOLUME [READONLY] [TARGET=<NAME>] - Attach selected volume");
-        }
-
-        public static void AttachISCSIDisk(Disk disk, string defaultTargetName, KeyValuePairList<string, string> parameters)
-        {
-            if (VerifyParameters(parameters, "readonly", "target"))
-            {
-                bool isReadOnly = parameters.ContainsKey("readonly");
-                disk.IsReadOnly |= isReadOnly;
-                if (disk is DiskImage)
-                {
-                    bool isLocked = ((DiskImage)disk).ExclusiveLock();
-                    if (!isLocked)
-                    {
-                        Console.WriteLine("Error: Cannot lock the disk image for exclusive access");
-                        return;
-                    }
-                }
-
-                ISCSITarget target = null;
-                string targetName = defaultTargetName;
-                if (parameters.ContainsKey("target"))
-                {
-                    string name = parameters.ValueOf("target");
-                    if (ISCSINameHelper.IsValidISCSIName(name))
-                    {
-                        targetName = name;
-                    }
-                    else if (ISCSINameHelper.IsValidSubQualifier(name))
-                    {
-                        targetName = DefaultTargetIQN + ":" + name;
-                    }
-                    else
-                    {
-                        Console.WriteLine("Invalid parameter.");
-                        HelpAttach();
-                    }
-                }
-
-                target = FindTarget(targetName);
-
-                if (target == null)
-                {
-                    target = AddTarget(targetName);
-                }
-
-                ((VirtualSCSITarget)target.SCSITarget).Disks.Add(disk);
-                Console.WriteLine("Disk added to target: {0}", target.TargetName);
-            }
-            else
-            {
-                HelpAttach();
-            }
-        }
-
-        public static ISCSITarget AddTarget(string targetName)
-        {
-            List<Disk> disks = new List<Disk>();
-            VirtualSCSITarget scsiTarget = new VirtualSCSITarget(disks);
-            scsiTarget.OnLogEntry += new EventHandler<LogEntry>(OnLogEntry);
-            ISCSITarget target = new ISCSITarget(targetName, scsiTarget);
-            m_targets.Add(target);
-            return target;
-        }
-
-        public static ISCSITarget FindTarget(string targetName)
-        {
-            foreach (ISCSITarget target in m_targets)
-            {
-                // iSCSI names are not case sensitive
-                if (target.TargetName.ToLower() == targetName.ToLower())
-                {
-                    return target;
-                }
-            }
-            return null;
-        }
-    }
-}

+ 0 - 105
ISCSIConsole/Program.CreateCommand.cs

@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using DiskAccessLibrary;
-using DiskAccessLibrary.LogicalDiskManager;
-using DiskAccessLibrary.VHD;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        public static void CreateCommand(string[] args)
-        {
-            if (args.Length >= 2)
-            {
-                if (args[1].ToLower() == "vdisk")
-                {
-                    KeyValuePairList<string, string> parameters = ParseParameters(args, 2);
-                    CreateVDisk(parameters);
-                }
-                else
-                {
-                    Console.WriteLine("Invalid argument.");
-                    HelpCreate();
-                }
-            }
-            else
-            {
-                HelpCreate();
-            }
-        }
-
-        public static void CreateVDisk(KeyValuePairList<string, string> parameters)
-        {
-            if (!VerifyParameters(parameters, "file", "size"))
-            {
-                Console.WriteLine();
-                Console.WriteLine("Invalid parameter.");
-                HelpCreate();
-                return;
-            }
-
-            long sizeInBytes;
-
-            if (parameters.ContainsKey("size"))
-            {
-                long requestedSizeInMB = Conversion.ToInt64(parameters.ValueOf("size"), 0);
-                sizeInBytes = requestedSizeInMB * 1024 * 1024;
-                if (requestedSizeInMB <= 0)
-                {
-                    Console.WriteLine("Invalid size (must be specified in MB).");
-                    return;
-                }
-            }
-            else
-            {
-                Console.WriteLine("The SIZE parameter must be specified.");
-                return;
-            }
-
-            if (parameters.ContainsKey("file"))
-            {
-                string path = parameters.ValueOf("file");
-
-                if (new FileInfo(path).Exists)
-                {
-                    Console.WriteLine("Error: file already exists.");
-                    return;
-                }
-
-                try
-                {
-                    m_selectedDisk = VirtualHardDisk.Create(path, sizeInBytes);
-                    Console.WriteLine("The virtual disk file was created successfully.");
-                }
-                catch (IOException ex)
-                {
-                    Console.WriteLine("Error: Could not write the virtual disk file. {0}", ex.Message);
-                    return;
-                }
-                catch (UnauthorizedAccessException)
-                {
-                    Console.WriteLine("Error: Access Denied, Could not write the virtual disk file.");
-                    return;
-                }
-            }
-            else
-            {
-                Console.WriteLine("The FILE parameter was not specified.");
-            }
-        }
-
-        public static void HelpCreate()
-        {
-            Console.WriteLine();
-            Console.WriteLine("CREATE VDISK FILE=<path> SIZE=<N>");
-            Console.WriteLine();
-            Console.WriteLine("Note:");
-            Console.WriteLine("-----");
-            Console.WriteLine("1. SIZE must be specified in MB, and without any suffixes.");
-        }
-    }
-}

+ 0 - 104
ISCSIConsole/Program.DetailCommand.cs

@@ -1,104 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using DiskAccessLibrary;
-using DiskAccessLibrary.LogicalDiskManager;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        public static void DetailCommand(string[] args)
-        {
-            if (args.Length == 2)
-            {
-                switch (args[1].ToLower())
-                {
-                    case "disk":
-                        {
-                            Console.WriteLine();
-                            if (m_selectedDisk != null)
-                            {
-                                Console.WriteLine("Size: {0} bytes", m_selectedDisk.Size.ToString("###,###,###,###,##0"));
-                                if (m_selectedDisk is PhysicalDisk)
-                                {
-                                    PhysicalDisk disk = (PhysicalDisk)m_selectedDisk;
-                                    Console.WriteLine("Geometry: Heads: {0}, Cylinders: {1}, Sectors Per Track: {2}", disk.TracksPerCylinder, disk.Cylinders, disk.SectorsPerTrack);
-                                    Console.WriteLine();
-                                }
-                                else if (m_selectedDisk is DiskImage)
-                                {
-                                    DiskImage disk = (DiskImage)m_selectedDisk;
-                                    Console.WriteLine("Disk image path: {0}", disk.Path);
-                                    Console.WriteLine();
-                                }
-                                
-                                MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(m_selectedDisk);
-                                if (mbr != null)
-                                {
-                                    Console.WriteLine("Partitioning scheme: " + (mbr.IsGPTBasedDisk ? "GPT" : "MBR"));
-                                }
-                                DynamicDisk dynamicDisk = DynamicDisk.ReadFromDisk(m_selectedDisk);
-                                Console.WriteLine("Disk type: " + ((dynamicDisk != null) ? "Dynamic Disk" : "Basic Disk"));
-                            }
-                            else
-                            {
-                                Console.WriteLine("No disk has been selected.");
-                            }
-                            break;
-                        }
-                    case "volume":
-                    case "partition":
-                        {
-                            Console.WriteLine();
-                            if (m_selectedVolume != null)
-                            {
-                                Console.WriteLine("Volume size: {0} bytes", m_selectedVolume.Size.ToString("###,###,###,###,##0"));
-                                if (m_selectedVolume is GPTPartition)
-                                {
-                                    Console.WriteLine("Partition name: {0}", ((GPTPartition)m_selectedVolume).PartitionName);
-                                }
-
-                                Guid? windowsVolumeGuid = WindowsVolumeHelper.GetWindowsVolumeGuid(m_selectedVolume);
-                                if (windowsVolumeGuid.HasValue)
-                                {
-                                    List<string> mountPoints = WindowsVolumeManager.GetMountPoints(windowsVolumeGuid.Value);
-                                    foreach (string volumePath in mountPoints)
-                                    {
-                                        Console.WriteLine("Volume path: {0}", volumePath);
-                                    }
-                                    bool isMounted = WindowsVolumeManager.IsMounted(windowsVolumeGuid.Value);
-                                    Console.WriteLine("Mounted: {0}", isMounted);
-                                }
-                            }
-                            else
-                            {
-                                Console.WriteLine("No volume has been selected.");
-                            }
-                            break;
-                        }
-                    default:
-                        Console.WriteLine("Invalid argument.");
-                        HelpDetail();
-                        break;
-                }
-            }
-            else if (args.Length > 2)
-            {
-                Console.WriteLine("Too many arguments.");
-                HelpDetail();
-            }
-            else
-            {
-                HelpDetail();
-            }
-        }
-
-        public static void HelpDetail()
-        {
-            Console.WriteLine();
-            Console.WriteLine("DETAIL DISK       - Display selected disk details");
-            Console.WriteLine("DETAIL VOLUME     - Display selected volume details");
-        }
-    }
-}

+ 0 - 71
ISCSIConsole/Program.HelpCommand.cs

@@ -1,71 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        public static void HelpCommand(string[] args)
-        {
-            if (args.Length == 1)
-            {
-                Console.WriteLine();
-                Console.WriteLine("Available commands:");
-                Console.WriteLine("-------------------");
-                Console.WriteLine("ATTACH  - Attach selected disk or volume to an iSCSI target.");
-                Console.WriteLine("CREATE  - Create a new VHD.");
-                Console.WriteLine("DETAIL  - Provide details about a selected object.");
-                Console.WriteLine("LIST    - List disks, volumes, partitions or volume extents.");
-                Console.WriteLine("ONLINE  - Takes the selected disk online.");
-                Console.WriteLine("OFFLINE - Takes the selected disk offline.");
-                Console.WriteLine("SELECT  - Select disk, volume, partition or extent.");
-                Console.WriteLine("SET     - Set program variables.");
-                Console.WriteLine("START   - Start the iSCSI Server");
-                Console.WriteLine("STOP    - Stop the iSCSI Server");
-                Console.WriteLine();
-                Console.WriteLine("- Use the 'HELP XXX' command for help regarding command XXX.");
-            }
-            else
-            {
-                switch (args[1].ToLower())
-                {
-                    case "attach":
-                        HelpAttach();
-                        break;
-                    case "create":
-                        HelpCreate();
-                        break;
-                    case "detail":
-                        HelpDetail();
-                        break;
-                    case "list":
-                        HelpList();
-                        break;
-                    case "offline":
-                        HelpOffline();
-                        break;
-                    case "online":
-                        HelpOnline();
-                        break;
-                    case "select":
-                        HelpSelect();
-                        break;
-                    case "set":
-                        HelpSet();
-                        break;
-                    case "start":
-                        HelpStart();
-                        break;
-                    case "stop":
-                        HelpStop();
-                        break;
-                    default:
-                        Console.WriteLine("No such command: {0}", args[1]);
-                        break;
-                }
-            }
-        }
-    }
-}

+ 0 - 227
ISCSIConsole/Program.ListCommand.cs

@@ -1,227 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using DiskAccessLibrary.LogicalDiskManager;
-using DiskAccessLibrary;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    partial class Program
-    {
-        public static void ListCommand(string[] args)
-        {
-            if (args.Length >= 2)
-            {
-                switch (args[1].ToLower())
-                {
-                    case "disk":
-                        Console.WriteLine();
-                        ListPhysicalDisks();
-                        break;
-                    case "partition":
-                        Console.WriteLine();
-                        ListPartitions();
-                        break;
-                    case "volume":
-                        Console.WriteLine();
-                        ListVolumes();
-                        break;
-                    case "extent":
-                        Console.WriteLine();
-                        ListExtents();
-                        break;
-                    default:
-                        Console.WriteLine();
-                        Console.WriteLine("Invalid parameter.");
-                        HelpList();
-                        break;
-                }
-            }
-            else
-            {
-                HelpList();
-            }
-        }
-
-        public static void HelpList()
-        {
-            Console.WriteLine();
-            Console.WriteLine("LIST DISK      - Print a list of physical disks.");
-            Console.WriteLine("LIST PARTITION - Print a list of partitions on the selected disk.");
-            Console.WriteLine("LIST VOLUME    - Print a list of supported volumes.");
-            Console.WriteLine("LIST EXTENT    - Print a list of extents of the selected volume.");
-        }
-
-        public static void ListPhysicalDisks()
-        {
-            List<PhysicalDisk> disks = PhysicalDiskHelper.GetPhysicalDisks();
-
-            Console.WriteLine("Disk ##  Size     GPT  Dyn  DiskID  Disk Group Name   ");
-            Console.WriteLine("-------  -------  ---  ---  ------  ------------------");
-            foreach (PhysicalDisk disk in disks)
-            {
-                int index = disk.PhysicalDiskIndex;
-
-                string diskNumber = index.ToString().PadLeft(2);
-                MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk);
-                string isGPTStr = (mbr != null && mbr.IsGPTBasedDisk) ? " * " : "   ";
-                string isDynStr = DynamicDisk.IsDynamicDisk(disk) ? " * " : "   ";
-                string diskID = String.Empty;
-                string diskGroupName = String.Empty;
-                VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(disk);
-                if (database != null)
-                {
-                    PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk);
-                    DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid);
-                    diskID = diskRecord.DiskId.ToString();
-                    diskGroupName = database.DiskGroupName; 
-                }
-
-                diskID = diskID.PadLeft(6);
-                Console.WriteLine("Disk {0}  {1}  {2}  {3}  {4}  {5}", diskNumber, FormattingHelper.GetStandardSizeString(disk.Size), isGPTStr, isDynStr, diskID, diskGroupName);
-            }
-        }
-
-        public static void ListPartitions()
-        {
-            if (m_selectedDisk != null)
-            {
-                List<Partition> partitions = BasicDiskHelper.GetPartitions(m_selectedDisk);
-                Console.WriteLine("Partition #  Type              Size     Offset   Start Sector");
-                Console.WriteLine("-----------  ----------------  -------  -------  ------------");
-                for (int index = 0; index < partitions.Count; index++)
-                {
-                    Partition partition = partitions[index];
-                    long offset = partition.FirstSector * m_selectedDisk.BytesPerSector;
-                    long size = partition.Size;
-                    string partitionType;
-                    if (partition is GPTPartition)
-                    {
-                        partitionType = ((GPTPartition)partition).PartitionTypeName;
-                    }
-                    else // partition is MBRPartition
-                    {
-                        partitionType = ((MBRPartition)partition).PartitionTypeName.ToString();
-                    }
-                    partitionType = partitionType.PadRight(16);
-                    string startSector = partition.FirstSector.ToString().PadLeft(12);
-                    Console.WriteLine("Partition {0}  {1}  {2}  {3}  {4}", index.ToString(), partitionType, FormattingHelper.GetStandardSizeString(size), FormattingHelper.GetStandardSizeString(offset), startSector);
-                }
-            }
-            else
-            {
-                Console.WriteLine("No disk has been selected");
-            }
-        }
-
-        public static void ListVolumes()
-        {
-            List<Volume> volumes = WindowsVolumeHelper.GetVolumes();
-            Console.WriteLine("Volume ##  ID    Name          Type       Size     Status   ");
-            Console.WriteLine("---------  ----  ------------  ---------  -------  ---------");
-
-            for (int index = 0; index < volumes.Count; index++)
-            {
-                Volume volume = volumes[index];
-                string type = VolumeHelper.GetVolumeTypeString(volume);
-                string status = VolumeHelper.GetVolumeStatusString(volume);
-
-                ulong volumeID = 0;
-                string name = String.Empty;
-
-                if (volume is DynamicVolume)
-                {
-                    volumeID = ((DynamicVolume)volume).VolumeID;
-                    name = ((DynamicVolume)volume).Name;
-                }
-
-                string volumeNumber = index.ToString().PadLeft(2);
-                type = type.ToString().PadRight(9);
-                name = name.ToString().PadRight(12);
-                status = status.ToString().PadRight(9);
-
-                string volumeIDString = String.Empty;
-                if (volumeID != 0)
-                {
-                    volumeIDString = volumeID.ToString();
-                }
-                volumeIDString = volumeIDString.PadRight(4);
-
-                Console.WriteLine("Volume {0}  {1}  {2}  {3}  {4}  {5}", volumeNumber, volumeIDString, name, type, FormattingHelper.GetStandardSizeString(volume.Size), status);
-            }
-        }
-
-        public static void ListExtents()
-        {
-            if (m_selectedVolume != null)
-            {
-                Console.WriteLine("Extent ##  ID    Name       Size     DiskID  Offset   Start Sector");
-                Console.WriteLine("---------  ----  ---------  -------  ------  -------  ------------");
-
-                for (int index = 0; index < m_selectedVolume.Extents.Count; index++)
-                {
-                    DiskExtent extent = m_selectedVolume.Extents[index];
-
-                    string extentNumber = index.ToString().PadLeft(2);
-                    ulong extentID = 0;
-                    ulong diskID = 0;
-                    string name = String.Empty;
-                    
-                    if (extent is DynamicDiskExtent)
-                    {
-                        extentID = ((DynamicDiskExtent)extent).ExtentID;
-                        name = ((DynamicDiskExtent)extent).Name;
-
-                        if (extent.Disk != null)
-                        {
-                            VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(extent.Disk);
-                            if (database != null)
-                            {
-                                ExtentRecord extentRecord = database.FindExtentByExtentID(extentID);
-                                diskID = extentRecord.DiskId;
-                            }
-                        }
-                    }
-
-                    string offsetString;
-                    if (extent.Disk != null)
-                    {
-                        long offset = extent.FirstSector * extent.Disk.BytesPerSector;
-                        offsetString = FormattingHelper.GetStandardSizeString(offset);
-                    }
-                    else
-                    {
-                        offsetString = "    N/A";
-                    }
-                    long size = extent.Size;
-
-                    name = name.ToString().PadRight(9);
-
-                    string extentIDString = String.Empty;
-                    if (extentID != 0)
-                    {
-                        extentIDString = extentID.ToString();
-                    }
-                    extentIDString = extentIDString.PadLeft(4);
-
-                    string diskIDString = String.Empty;
-                    if (diskID != 0)
-                    {
-                        diskIDString = diskID.ToString();
-                    }
-                    diskIDString = diskIDString.PadLeft(6);
-
-                    string startSector = extent.FirstSector.ToString().PadLeft(12);
-
-                    Console.WriteLine("Extent {0}  {1}  {2}  {3}  {4}  {5}  {6}", extentNumber, extentIDString, name, FormattingHelper.GetStandardSizeString(size), diskIDString, offsetString, startSector);
-                }
-            }
-            else
-            {
-                Console.WriteLine("No volume has been selected");
-            }
-        }
-    }
-}

+ 9 - 2
ISCSIConsole/Program.Log.cs

@@ -1,3 +1,9 @@
+/* Copyright (C) 2012-2016 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;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
@@ -10,17 +16,18 @@ namespace ISCSIConsole
     {
     {
         private static FileStream m_logFile;
         private static FileStream m_logFile;
 
 
-        public static void OpenLogFile(string logFilePath)
+        public static bool OpenLogFile(string logFilePath)
         {
         {
             try
             try
             {
             {
                 // We must avoid using buffered writes, using it will negatively affect the performance and reliability.
                 // We must avoid using buffered writes, using it will negatively affect the performance and reliability.
                 // Note: once the file system write buffer is filled, Windows may delay any (buffer-dependent) pending write operations, which will create a deadlock.
                 // Note: once the file system write buffer is filled, Windows may delay any (buffer-dependent) pending write operations, which will create a deadlock.
                 m_logFile = new FileStream(logFilePath, FileMode.Append, FileAccess.Write, FileShare.Read, 0x1000, FileOptions.WriteThrough);
                 m_logFile = new FileStream(logFilePath, FileMode.Append, FileAccess.Write, FileShare.Read, 0x1000, FileOptions.WriteThrough);
+                return true;
             }
             }
             catch
             catch
             {
             {
-                Console.WriteLine("Cannot open log file");
+                return false;
             }
             }
         }
         }
 
 

+ 0 - 177
ISCSIConsole/Program.SelectCommand.cs

@@ -1,177 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using DiskAccessLibrary;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        private static Disk m_selectedDisk;
-        private static Volume m_selectedVolume;
-
-        public static void SelectCommand(string[] args)
-        {
-            if (args.Length == 1)
-            {
-                HelpSelect();
-                return;
-            }
-
-            switch (args[1].ToLower())
-            {
-                case "disk":
-                    {
-                        if (args.Length == 3)
-                        {
-                            int diskIndex = Conversion.ToInt32(args[2], -1);
-                            if (diskIndex >= 0)
-                            {
-                                PhysicalDisk disk = null;
-                                try
-                                {
-                                    disk = new PhysicalDisk(diskIndex);
-                                }
-                                catch
-                                {
-                                    Console.WriteLine();
-                                    Console.WriteLine("Error: Invalid disk number");
-                                }
-
-                                if (disk != null)
-                                {
-                                    m_selectedDisk = disk;
-                                }
-                            }
-                        }
-                        else
-                        {
-                            Console.WriteLine();
-                            Console.WriteLine("Error: Invalid number of arguments");
-                        }
-                        break;
-                    }
-                case "vdisk":
-                    {
-                        if (args.Length == 3)
-                        {
-                            KeyValuePairList<string, string> parameters = ParseParameters(args, 2);
-                            if (parameters.ContainsKey("file"))
-                            {
-                                string path = parameters.ValueOf("file");
-                                if (new FileInfo(path).Exists)
-                                {
-                                    try
-                                    {
-                                        m_selectedDisk = DiskImage.GetDiskImage(path);
-                                    }
-                                    catch (InvalidDataException)
-                                    {
-                                        Console.WriteLine("Invalid virtual disk format");
-                                    }
-                                    catch (NotImplementedException)
-                                    {
-                                        Console.WriteLine("Unsupported virtual disk format");
-                                    }
-                                    catch (IOException ex)
-                                    {
-                                        Console.WriteLine("Cannot read file: " + ex.Message);
-                                    }
-                                }
-                                else
-                                {
-                                    Console.WriteLine("File not found: \"{0}\"", path);
-                                }
-                            }
-                            else
-                            {
-                                Console.WriteLine();
-                                Console.WriteLine("Error: Invalid argument");
-                            }
-                        }
-                        else
-                        {
-                            Console.WriteLine("Error: Invalid number of arguments");
-                            
-                        }
-                        break;
-                    }
-                case "partition":
-                    {
-                        if (m_selectedDisk != null) 
-                        {
-                            if (args.Length == 3)
-                            {
-                                int partitionIndex = Conversion.ToInt32(args[2], -1);
-                                List<Partition> partitions = BasicDiskHelper.GetPartitions(m_selectedDisk);
-                                if (partitionIndex >= 0 && partitionIndex < partitions.Count)
-                                {
-                                    m_selectedVolume = partitions[partitionIndex];
-                                }
-                                else
-                                {
-                                    Console.WriteLine("Error: Invalid partition number");
-                                }
-                            }
-                            else
-                            {
-                                Console.WriteLine();
-                                Console.WriteLine("Error: Partition number was not specified");
-                            }
-                        }
-                        else
-                        {
-                            Console.WriteLine("No disk has been selected");
-                        }
-                        break;
-                    }
-                case "volume":
-                    {
-                        if (args.Length == 3)
-                        {
-                            List<Volume> volumes;
-                            try
-                            {
-                                volumes = WindowsVolumeHelper.GetVolumes();
-                            }
-                            catch
-                            {
-                                volumes = new List<Volume>();
-                            }
-
-                            int volumeIndex = Conversion.ToInt32(args[2], -1);
-                            if (volumeIndex >= 0 && volumeIndex < volumes.Count)
-                            {
-                                m_selectedVolume = volumes[volumeIndex];
-                            }
-                            else
-                            {
-                                Console.WriteLine();
-                                Console.WriteLine("Error: Invalid volume number");
-                            }
-                        }
-                        else
-                        {
-                            Console.WriteLine();
-                            Console.WriteLine("Error: Volume number was not specified");
-                        }
-                        break;
-                    }
-                default:
-                    HelpSelect();
-                    break;
-            }
-        }
-
-        public static void HelpSelect()
-        {
-            Console.WriteLine();
-            Console.WriteLine("SELECT DISK <N>          - Select physical disk.");
-            Console.WriteLine("SELECT VDISK FILE=<path> - Select virtual disk file.");
-            Console.WriteLine("SELECT VOLUME <N>        - Select volume.");
-            Console.WriteLine("SELECT PARTITION <N>     - Select partition.");
-        }
-    }
-}

+ 0 - 120
ISCSIConsole/Program.SetCommand.cs

@@ -1,120 +0,0 @@
-/* Copyright (C) 2012-2016 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.Text;
-using DiskAccessLibrary;
-using ISCSI.Server;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    public partial class Program
-    {
-        public static void SetCommand(string[] args)
-        {
-            if (args.Length == 2)
-            {
-                KeyValuePairList<string, string> parameters = ParseParameters(args, 1);
-                if (!VerifyParameters(parameters, "debug", "commandqueue", "MaxRecvDataSegmentLength".ToLower(), "MaxBurstLength".ToLower(), "FirstBurstLength".ToLower()))
-                {
-                    Console.WriteLine("Invalid parameter.");
-                    return;
-                }
-
-                if (parameters.ContainsKey("debug"))
-                {
-                    m_debug = true;
-                }
-
-                if (parameters.ContainsKey("CommandQueue".ToLower()))
-                {
-                    int requestedCommandQueueSize = Conversion.ToInt32(parameters.ValueOf("commandqueue"), 0);
-                    if (requestedCommandQueueSize < 0)
-                    {
-                        Console.WriteLine("Invalid queue size (must be non-negative).");
-                        return;
-                    }
-
-                    ISCSIServer.DefaultCommandQueueSize = (uint)requestedCommandQueueSize;
-                }
-
-                if (parameters.ContainsKey("MaxRecvDataSegmentLength".ToLower()))
-                {
-                    int requestedMaxRecvDataSegmentLength = Conversion.ToInt32(parameters.ValueOf("MaxRecvDataSegmentLength".ToLower()), 0);
-                    if (requestedMaxRecvDataSegmentLength <= 0)
-                    {
-                        Console.WriteLine("Invalid length (must be positive).");
-                        return;
-                    }
-
-                    ISCSIServer.DeclaredParameters.MaxRecvDataSegmentLength = requestedMaxRecvDataSegmentLength;
-                    Console.WriteLine("MaxRecvDataSegmentLength has been set to " + ISCSIServer.DesiredParameters.MaxBurstLength);
-                }
-
-                if (parameters.ContainsKey("MaxBurstLength".ToLower()))
-                {
-                    int requestedMaxBurstLength = Conversion.ToInt32(parameters.ValueOf("MaxBurstLength".ToLower()), 0);
-                    if (requestedMaxBurstLength <= 0)
-                    {
-                        Console.WriteLine("Invalid length (must be positive).");
-                        return;
-                    }
-
-                    ISCSIServer.DesiredParameters.MaxBurstLength = requestedMaxBurstLength;
-                    Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.DesiredParameters.MaxBurstLength);
-                    if (ISCSIServer.DesiredParameters.MaxBurstLength < ISCSIServer.DesiredParameters.FirstBurstLength)
-                    {
-                        // FirstBurstLength MUST NOT exceed MaxBurstLength
-                        ISCSIServer.DesiredParameters.FirstBurstLength = ISCSIServer.DesiredParameters.MaxBurstLength;
-                        Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.DesiredParameters.FirstBurstLength);
-                    }
-                }
-
-                if (parameters.ContainsKey("FirstBurstLength".ToLower()))
-                {
-                    int requestedFirstBurstLength = Conversion.ToInt32(parameters.ValueOf("FirstBurstLength".ToLower()), 0);
-                    if (requestedFirstBurstLength <= 0)
-                    {
-                        Console.WriteLine("Invalid length (must be positive).");
-                        return;
-                    }
-
-                    ISCSIServer.DesiredParameters.FirstBurstLength = requestedFirstBurstLength;
-                    Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.DesiredParameters.FirstBurstLength);
-                    if (ISCSIServer.DesiredParameters.MaxBurstLength < ISCSIServer.DesiredParameters.FirstBurstLength)
-                    {
-                        // FirstBurstLength MUST NOT exceed MaxBurstLength
-                        ISCSIServer.DesiredParameters.MaxBurstLength = ISCSIServer.DesiredParameters.FirstBurstLength;
-                        Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.DesiredParameters.MaxBurstLength);
-                    }
-                }
-            }
-            else if (args.Length > 2)
-            {
-                Console.WriteLine("Too many arguments.");
-                HelpSet();
-            }
-            else
-            {
-                HelpSet();
-            }
-        }
-
-        public static void HelpSet()
-        {
-            Console.WriteLine();
-            Console.WriteLine("SET CommandQueue=<N>             - Sets the iSCSI server command queue size.");
-            Console.WriteLine("SET MaxRecvDataSegmentLength=<N> - Declare this value to the initator.");
-            Console.WriteLine("SET MaxBurstLength=<N>           - Offer this value to the initator.");
-            Console.WriteLine("SET FirstBurstLength=<N>         - Offer this value to the initator.");
-            
-            Console.WriteLine();
-            Console.WriteLine("Command queue size can be set to 0 (no queue, single command at a time).");
-        }
-    }
-}

+ 0 - 110
ISCSIConsole/Program.StartCommand.cs

@@ -1,110 +0,0 @@
-/* Copyright (C) 2012-2016 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 System.Net.Sockets;
-using ISCSI.Server;
-using Utilities;
-
-namespace ISCSIConsole
-{
-    partial class Program
-    {
-        public const int DefaultISCSIPort = 3260;
-
-        private static List<ISCSITarget> m_targets = new List<ISCSITarget>();
-        private static ISCSIServer m_server;
-
-        public static void StartCommand(string[] args)
-        {
-            if (m_server == null)
-            {
-                if (m_targets.Count > 0)
-                {
-                    KeyValuePairList<string, string> parameters = ParseParameters(args, 1);
-                    if (!VerifyParameters(parameters, "port", "log"))
-                    {
-                        Console.WriteLine();
-                        Console.WriteLine("Invalid parameter");
-                        HelpStart();
-                        return;
-                    }
-
-                    int port = DefaultISCSIPort;
-                    if (parameters.ContainsKey("port"))
-                    {
-                        port = Conversion.ToInt32(parameters.ValueOf("port"), DefaultISCSIPort);
-                    }
-                    string logFile = String.Empty;
-                    if (parameters.ContainsKey("log"))
-                    {
-                        logFile = parameters.ValueOf("log");
-                    }
-                    m_server = new ISCSIServer();
-                    m_server.AddTargets(m_targets);
-                    m_server.OnLogEntry += new EventHandler<LogEntry>(OnLogEntry);
-                    if (logFile != String.Empty)
-                    {
-                        try
-                        {
-                            OpenLogFile(logFile);
-                        }
-                        catch (IOException)
-                        {
-                            Console.WriteLine("Could not append to log file");
-                            return;
-                        }
-                    }
-
-                    try
-                    {
-                        m_server.Start(port);
-                        Console.WriteLine("Server started, listening on port {0}", port);
-                    }
-                    catch (SocketException)
-                    {
-                        Console.WriteLine("Could not start iSCSI server");
-                        m_server.Stop();
-                        m_server = null;
-                    }
-                }
-                else
-                {
-                    Console.WriteLine("No disks have been attached");
-                }
-            }
-        }
-
-        public static void StopCommand(string[] args)
-        {
-            if (m_server != null)
-            {
-                m_server.Stop();
-                m_server = null;
-                Console.WriteLine("iSCSI target is stopping");
-                CloseLogFile();
-            }
-            else
-            {
-                Console.WriteLine("iSCSI target has not been started");
-            }
-        }
-
-        public static void HelpStart()
-        {
-            Console.WriteLine();
-            Console.WriteLine("ISCSI START [PORT=<port>] [LOG=<path>] - starts the iSCSI server");
-        }
-
-        public static void HelpStop()
-        {
-            Console.WriteLine();
-            Console.WriteLine("ISCSI STOP - stops the iSCSI server");
-        }
-    }
-}

+ 44 - 165
ISCSIConsole/Program.cs

@@ -1,203 +1,82 @@
+/* Copyright (C) 2016 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;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
-using System.Security.Principal;
-using System.Reflection;
 using System.Text;
 using System.Text;
-using DiskAccessLibrary.LogicalDiskManager;
-using DiskAccessLibrary;
-using Utilities;
+using System.Threading;
+using System.Windows.Forms;
 
 
 namespace ISCSIConsole
 namespace ISCSIConsole
 {
 {
-    partial class Program
+    public partial class Program
     {
     {
-        public static bool m_debug = false;
-
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
         static void Main(string[] args)
         static void Main(string[] args)
         {
         {
-            Console.WriteLine("iSCSI Console v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
-            Console.WriteLine("Author: Tal Aloni (tal.aloni.il@gmail.com)");
+            Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
+            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
 
 
-            MainLoop();
-        }
-
-        public static void MainLoop()
-        {
-            bool exit = false;
-            while (true)
+            if (args.Length > 0)
             {
             {
-                if (m_debug)
+                if (args[0] == "/help")
                 {
                 {
-                    exit = ProcessCommand();
+                    
                 }
                 }
-                else
+                if (args[0] == "/log")
                 {
                 {
-                    try
+                    string path = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
+                    if (!path.EndsWith(@"\"))
                     {
                     {
-                        exit = ProcessCommand();
+                        path += @"\";
                     }
                     }
-                    catch (Exception ex)
+                    path += String.Format("Log {0}.txt", DateTime.Now.ToString("yyyy-MM-dd HH-mm"));
+                    bool success = OpenLogFile(path);
+                    if (!success)
                     {
                     {
-                        Console.WriteLine("Unhandled exception: " + ex.ToString());
+                        MessageBox.Show("Cannot open log file", "Error");
                     }
                     }
                 }
                 }
-
-                if (exit)
-                {
-                    break;
-                }
-            }
-        }
-
-        /// <returns>true to exit</returns>
-        public static bool ProcessCommand()
-        {
-            Console.WriteLine();
-            Console.Write("iSCSI> ");
-            string command = Console.ReadLine();
-            string[] args = GetCommandArgsIgnoreEscape(command);
-            bool exit = false;
-            if (args.Length > 0)
-            {
-                string commandName = args[0];
-                switch (commandName.ToLower())
-                {
-                    case "attach":
-                        AttachCommand(args);
-                        break;
-                    case "create":
-                        CreateCommand(args);
-                        break;
-                    case "detail":
-                        DetailCommand(args);
-                        break;
-                    case "exit":
-                        exit = true;
-                        if (m_server != null)
-                        {
-                            m_server.Stop();
-                            m_server = null;
-                        }
-                        break;
-                    case "help":
-                        {
-                            HelpCommand(args);
-                            break;
-                        }
-                    case "list":
-                        ListCommand(args);
-                        break;
-                    case "offline":
-                        OfflineCommand(args);
-                        break;
-                    case "online":
-                        OnlineCommand(args);
-                        break;
-                    case "select":
-                        SelectCommand(args);
-                        break;
-                    case "set":
-                        SetCommand(args);
-                        break;
-                    case "start":
-                        StartCommand(args);
-                        break;
-                    case "stop":
-                        StopCommand(args);
-                        break;
-                    default:
-                        Console.WriteLine("Invalid command. use the 'HELP' command to see the list of commands.");
-                        break;
-                }
-            }
-            return exit;
-        }
-
-        public static KeyValuePairList<string, string> ParseParameters(string[] args, int start)
-        {
-            KeyValuePairList<string, string> result = new KeyValuePairList<string, string>();
-            for (int index = start; index < args.Length; index++)
-            {
-                string[] pair = args[index].Split('=');
-                if (pair.Length >= 2)
-                {
-                    string key = pair[0].ToLower(); // we search by the key, so it should be set to lowercase
-                    string value = pair[1];
-                    value = Unquote(value);
-                    result.Add(key, value);
-                }
                 else
                 else
                 {
                 {
-                    result.Add(pair[0].ToLower(), String.Empty);
-                }
-            }
-            return result;
-        }
-
-        /// <summary>
-        /// Make sure all given parameters are allowed
-        /// </summary>
-        public static bool VerifyParameters(KeyValuePairList<string, string> parameters, params string[] allowedKeys)
-        {
-            List<string> allowedList = new List<string>(allowedKeys);
-            List<string> keys = parameters.Keys;
-            foreach(string key in keys)
-            {
-                if (!allowedList.Contains(key))
-                {
-                    return false;
+                    StringBuilder builder = new StringBuilder();
+                    builder.AppendLine("Command line arguments:");
+                    builder.AppendLine("/log - will write log file to executable directory");
+                    MessageBox.Show(builder.ToString(), "Error");
+                    return;
                 }
                 }
             }
             }
-            return true;
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new MainForm());
         }
         }
 
 
-        private static int IndexOfUnquotedSpace(string str)
+        public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
         {
         {
-            return IndexOfUnquotedSpace(str, 0);
+            HandleUnhandledException(e.Exception);
         }
         }
 
 
-        private static int IndexOfUnquotedSpace(string str, int startIndex)
+        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         {
         {
-            return QuotedStringUtils.IndexOfUnquotedChar(str, ' ', startIndex);
-        }
-
-        public static string Unquote(string str)
-        {
-            string quote = '"'.ToString();
-            if (str.StartsWith(quote) && str.EndsWith(quote))
+            if (e.ExceptionObject != null)
             {
             {
-                return str.Substring(1, str.Length - 2);
-            }
-            else
-            {
-                return str;
+                Exception ex = (Exception)e.ExceptionObject;
+                HandleUnhandledException(ex);
             }
             }
         }
         }
 
 
-        private static string[] GetCommandArgsIgnoreEscape(string commandLine)
+        private static void HandleUnhandledException(Exception ex)
         {
         {
-            List<string> argsList = new List<string>();
-            int endIndex = IndexOfUnquotedSpace(commandLine);
-            int startIndex = 0;
-            while (endIndex != -1)
-            {
-                int length = endIndex - startIndex;
-                string nextArg = commandLine.Substring(startIndex, length);
-                nextArg = Unquote(nextArg);
-                argsList.Add(nextArg);
-                startIndex = endIndex + 1;
-                endIndex = IndexOfUnquotedSpace(commandLine, startIndex);
-            }
-
-            string lastArg = commandLine.Substring(startIndex);
-            lastArg = Unquote(lastArg);
-            if (lastArg != String.Empty)
-            {
-                argsList.Add(lastArg);
-            }
-
-            return argsList.ToArray();
+            string message = String.Format("Exception: {0}: {1} Source: {2} {3}", ex.GetType(), ex.Message, ex.Source, ex.StackTrace);
+            MessageBox.Show(message, "Error");
+            Application.Exit();
         }
         }
     }
     }
 }
 }

+ 139 - 0
ISCSIConsole/SelectDiskImageForm.Designer.cs

@@ -0,0 +1,139 @@
+namespace ISCSIConsole
+{
+    partial class SelectDiskImageForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SelectDiskImageForm));
+            this.lblFilePath = new System.Windows.Forms.Label();
+            this.txtFilePath = new System.Windows.Forms.TextBox();
+            this.btnBrowse = new System.Windows.Forms.Button();
+            this.btnOK = new System.Windows.Forms.Button();
+            this.btnCancel = new System.Windows.Forms.Button();
+            this.checkBox1 = new System.Windows.Forms.CheckBox();
+            this.openDiskImageDialog = new System.Windows.Forms.OpenFileDialog();
+            this.SuspendLayout();
+            // 
+            // lblFilePath
+            // 
+            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.TabIndex = 3;
+            this.lblFilePath.Text = "File:";
+            // 
+            // txtFilePath
+            // 
+            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;
+            // 
+            // btnBrowse
+            // 
+            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);
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(224, 88);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 6;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(305, 88);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 7;
+            this.btnCancel.Text = "Cancel";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
+            // 
+            // checkBox1
+            // 
+            this.checkBox1.AutoSize = true;
+            this.checkBox1.Location = new System.Drawing.Point(12, 92);
+            this.checkBox1.Name = "checkBox1";
+            this.checkBox1.Size = new System.Drawing.Size(74, 17);
+            this.checkBox1.TabIndex = 8;
+            this.checkBox1.Text = "Read only";
+            this.checkBox1.UseVisualStyleBackColor = true;
+            // 
+            // openDiskImageDialog
+            // 
+            this.openDiskImageDialog.Filter = "All Supported Disk Images (*.vhd,*.vmdk,*.img)|*.vhd;*.vmdk;*.img|Virtual Hard Di" +
+                "sk (*.vhd)|*.vhd|Virtual Machine Disk (*.vmdk)|*.vmdk|Raw Disk Image (*.img)|*.i" +
+                "mg|All Files (*.*)|*.*";
+            // 
+            // 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.Controls.Add(this.checkBox1);
+            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.MinimumSize = new System.Drawing.Size(400, 150);
+            this.Name = "SelectDiskImageForm";
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+            this.Text = "Select Disk Image";
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label lblFilePath;
+        private System.Windows.Forms.TextBox txtFilePath;
+        private System.Windows.Forms.Button btnBrowse;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.CheckBox checkBox1;
+        private System.Windows.Forms.OpenFileDialog openDiskImageDialog;
+    }
+}

+ 73 - 0
ISCSIConsole/SelectDiskImageForm.cs

@@ -0,0 +1,73 @@
+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
+{
+    public partial class SelectDiskImageForm : Form
+    {
+        private DiskImage m_diskImage;
+
+        public SelectDiskImageForm()
+        {
+            InitializeComponent();
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = DialogResult.Cancel;
+            this.Close();
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            string path = txtFilePath.Text;
+            if (path == String.Empty)
+            {
+                MessageBox.Show("Please choose file location.", "Error");
+                return;
+            }
+            DiskImage diskImage;
+            try
+            {
+                diskImage = DiskImage.GetDiskImage(path);
+            }
+            catch (IOException)
+            {
+                MessageBox.Show("Can't open disk image.", "Error");
+                return;
+            }
+            bool isLocked = diskImage.ExclusiveLock();
+            if (!isLocked)
+            {
+                MessageBox.Show("Cannot lock the disk image for exclusive access.", "Error");
+                return;
+            }
+            m_diskImage = diskImage;
+            this.DialogResult = DialogResult.OK;
+            this.Close();
+        }
+
+        private void btnBrowse_Click(object sender, EventArgs e)
+        {
+            DialogResult result = openDiskImageDialog.ShowDialog();
+            if (result == DialogResult.OK)
+            {
+                txtFilePath.Text = openDiskImageDialog.FileName;
+            }
+        }
+
+        public DiskImage DiskImage
+        {
+            get
+            {
+                return m_diskImage;
+            }
+        }
+    }
+}

File diff suppressed because it is too large
+ 6296 - 0
ISCSIConsole/SelectDiskImageForm.resx


+ 30 - 0
ISCSIConsole/Win32/SecurityHelper.cs

@@ -0,0 +1,30 @@
+/* Copyright (C) 2012-2016 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.Security.Principal;
+
+namespace ISCSIConsole
+{
+    public class SecurityHelper
+    {
+        public static bool IsAdministrator()
+        {
+            WindowsIdentity windowsIdentity = null;
+            try
+            {
+                windowsIdentity = WindowsIdentity.GetCurrent();
+            }
+            catch
+            {
+                return false;
+            }
+            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
+            return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
+        }
+    }
+}

+ 143 - 0
ISCSIConsole/Win32/SelectPhysicalDiskForm.Designer.cs

@@ -0,0 +1,143 @@
+namespace ISCSIConsole
+{
+    partial class SelectPhysicalDiskForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SelectPhysicalDiskForm));
+            this.btnCancel = new System.Windows.Forms.Button();
+            this.btnOK = new System.Windows.Forms.Button();
+            this.chkReadOnly = new System.Windows.Forms.CheckBox();
+            this.listPhysicalDisks = new System.Windows.Forms.ListView();
+            this.columnDisk = new System.Windows.Forms.ColumnHeader();
+            this.columnDescription = new System.Windows.Forms.ColumnHeader();
+            this.columnSerialNumber = new System.Windows.Forms.ColumnHeader();
+            this.columnSize = new System.Windows.Forms.ColumnHeader();
+            this.SuspendLayout();
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(405, 191);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 1;
+            this.btnCancel.Text = "Cancel";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(324, 191);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 2;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // chkReadOnly
+            // 
+            this.chkReadOnly.AutoSize = true;
+            this.chkReadOnly.Location = new System.Drawing.Point(12, 195);
+            this.chkReadOnly.Name = "chkReadOnly";
+            this.chkReadOnly.Size = new System.Drawing.Size(76, 17);
+            this.chkReadOnly.TabIndex = 3;
+            this.chkReadOnly.Text = "Read Only";
+            this.chkReadOnly.UseVisualStyleBackColor = true;
+            // 
+            // listPhysicalDisks
+            // 
+            this.listPhysicalDisks.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.columnDisk,
+            this.columnDescription,
+            this.columnSerialNumber,
+            this.columnSize});
+            this.listPhysicalDisks.FullRowSelect = true;
+            this.listPhysicalDisks.Location = new System.Drawing.Point(12, 12);
+            this.listPhysicalDisks.Name = "listPhysicalDisks";
+            this.listPhysicalDisks.Size = new System.Drawing.Size(468, 173);
+            this.listPhysicalDisks.TabIndex = 4;
+            this.listPhysicalDisks.UseCompatibleStateImageBehavior = false;
+            this.listPhysicalDisks.View = System.Windows.Forms.View.Details;
+            this.listPhysicalDisks.ColumnWidthChanging += new System.Windows.Forms.ColumnWidthChangingEventHandler(this.listPhysicalDisks_ColumnWidthChanging);
+            // 
+            // columnDisk
+            // 
+            this.columnDisk.Text = "Disk";
+            // 
+            // columnDescription
+            // 
+            this.columnDescription.Text = "Description";
+            this.columnDescription.Width = 210;
+            // 
+            // columnSerialNumber
+            // 
+            this.columnSerialNumber.Text = "Serial Number";
+            this.columnSerialNumber.Width = 134;
+            // 
+            // columnSize
+            // 
+            this.columnSize.Text = "Size";
+            this.columnSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+            // 
+            // SelectPhysicalDiskForm
+            // 
+            this.AcceptButton = this.btnOK;
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            this.CancelButton = this.btnCancel;
+            this.ClientSize = new System.Drawing.Size(494, 225);
+            this.Controls.Add(this.listPhysicalDisks);
+            this.Controls.Add(this.chkReadOnly);
+            this.Controls.Add(this.btnOK);
+            this.Controls.Add(this.btnCancel);
+            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(500, 250);
+            this.MinimumSize = new System.Drawing.Size(500, 250);
+            this.Name = "SelectPhysicalDiskForm";
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+            this.Text = "Select Physical Disk";
+            this.Load += new System.EventHandler(this.SelectPhysicalDiskForm_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.CheckBox chkReadOnly;
+        private System.Windows.Forms.ListView listPhysicalDisks;
+        private System.Windows.Forms.ColumnHeader columnDisk;
+        private System.Windows.Forms.ColumnHeader columnDescription;
+        private System.Windows.Forms.ColumnHeader columnSerialNumber;
+        private System.Windows.Forms.ColumnHeader columnSize;
+    }
+}

+ 153 - 0
ISCSIConsole/Win32/SelectPhysicalDiskForm.cs

@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using DiskAccessLibrary;
+using DiskAccessLibrary.LogicalDiskManager;
+using Utilities;
+
+namespace ISCSIConsole
+{
+    public partial class SelectPhysicalDiskForm : Form
+    {
+        private PhysicalDisk m_selectedDisk;
+
+        public SelectPhysicalDiskForm()
+        {
+            InitializeComponent();
+        }
+
+        private void SelectPhysicalDiskForm_Load(object sender, EventArgs e)
+        {
+            List<PhysicalDisk> physicalDisks = PhysicalDiskHelper.GetPhysicalDisks();
+            if (Environment.OSVersion.Version.Major >= 6)
+            {
+                listPhysicalDisks.Columns.Add("Status", 60);
+                columnDescription.Width -= 60;
+            }
+            foreach (PhysicalDisk physicalDisk in physicalDisks)
+            {
+                string title = String.Format("Disk {0}", physicalDisk.PhysicalDiskIndex);
+                string description = physicalDisk.Description;
+                string serialNumber = physicalDisk.SerialNumber;
+                string sizeString = FormattingHelper.GetStandardSizeString(physicalDisk.Size);
+                ListViewItem item = new ListViewItem(title);
+                item.SubItems.Add(description);
+                item.SubItems.Add(serialNumber);
+                item.SubItems.Add(sizeString);
+                if (Environment.OSVersion.Version.Major >= 6)
+                {
+                    bool isOnline = physicalDisk.GetOnlineStatus();
+                    string status = isOnline ? "Online" : "Offline";
+                    item.SubItems.Add(status);
+                }
+                item.Tag = physicalDisk;
+                listPhysicalDisks.Items.Add(item);
+            }
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            PhysicalDisk selectedDisk;
+            if (listPhysicalDisks.SelectedItems.Count > 0)
+            {
+                selectedDisk = (PhysicalDisk)listPhysicalDisks.SelectedItems[0].Tag;
+            }
+            else
+            {
+                MessageBox.Show("No disk was selected", "Error");
+                return;
+            }
+            if (!chkReadOnly.Checked)
+            {
+                if (Environment.OSVersion.Version.Major >= 6)
+                {
+                    bool isDiskReadOnly;
+                    bool isOnline = selectedDisk.GetOnlineStatus(out isDiskReadOnly);
+                    if (isDiskReadOnly)
+                    {
+                        MessageBox.Show("The selected disk is set to readonly", "Error");
+                        return;
+                    }
+
+                    if (isOnline)
+                    {
+                        DialogResult result = MessageBox.Show("The selected disk will now be taken offline. OK?", String.Empty, MessageBoxButtons.OKCancel);
+                        if (result == DialogResult.OK)
+                        {
+                            bool success = selectedDisk.SetOnlineStatus(false);
+                            if (!success)
+                            {
+                                MessageBox.Show("Was not able to take the disk offline", "Error");
+                                return;
+                            }
+                        }
+                        else
+                        {
+                            return;
+                        }
+                    }
+                }
+                else
+                {
+                    if (DynamicDisk.IsDynamicDisk(selectedDisk))
+                    {
+                        // The user will probably want to stop the Logical Disk Manager services (vds, dmadmin, dmserver)
+                        // and lock all dynamic disks and dynamic volumes before whatever he's doing.
+                        // Modifications the the LDM database should be applied to all dynamic disks.
+                        DialogResult result = MessageBox.Show("The dynamic disk database will likely be corrupted, Continue?", "Warning", MessageBoxButtons.YesNo);
+                        if (result != DialogResult.Yes)
+                        {
+                            return;
+                        }
+                    }
+                    else
+                    {
+                        // Locking a disk does not prevent Windows from accessing mounted volumes on it. (it does prevent creation of new volumes).
+                        // For basic disks we need to lock the Disk and Volumes, and we should also call UpdateDiskProperties() after releasing the lock.
+                        LockStatus status = LockHelper.LockBasicDiskAndVolumesOrNone(selectedDisk);
+                        if (status == LockStatus.CannotLockDisk)
+                        {
+                            MessageBox.Show("Unable to lock the disk", "Error");
+                            return;
+                        }
+                        else if (status == LockStatus.CannotLockVolume)
+                        {
+                            MessageBox.Show("Unable to lock one of the volumes on the disk", "Error");
+                            return;
+                        }
+                    }
+                }
+            }
+            if (chkReadOnly.Checked)
+            {
+                selectedDisk.IsReadOnly = true;
+            }
+            m_selectedDisk = selectedDisk;
+            this.DialogResult = DialogResult.OK;
+            this.Close();
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = DialogResult.Cancel;
+            this.Close();
+        }
+
+        public PhysicalDisk SelectedDisk
+        {
+            get
+            {
+                return m_selectedDisk;
+            }
+        }
+
+        private void listPhysicalDisks_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
+        {
+            e.NewWidth = ((ListView)sender).Columns[e.ColumnIndex].Width;
+            e.Cancel = true;
+        }
+    }
+}

File diff suppressed because it is too large
+ 6293 - 0
ISCSIConsole/Win32/SelectPhysicalDiskForm.resx


+ 150 - 0
ISCSIConsole/Win32/SelectVolumeForm.Designer.cs

@@ -0,0 +1,150 @@
+namespace ISCSIConsole
+{
+    partial class SelectVolumeForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SelectVolumeForm));
+            this.btnCancel = new System.Windows.Forms.Button();
+            this.btnOK = new System.Windows.Forms.Button();
+            this.chkReadOnly = new System.Windows.Forms.CheckBox();
+            this.listPhysicalDisks = new System.Windows.Forms.ListView();
+            this.columnVolume = new System.Windows.Forms.ColumnHeader();
+            this.columnName = new System.Windows.Forms.ColumnHeader();
+            this.columnType = new System.Windows.Forms.ColumnHeader();
+            this.columnStatus = new System.Windows.Forms.ColumnHeader();
+            this.columnSize = new System.Windows.Forms.ColumnHeader();
+            this.SuspendLayout();
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(405, 191);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 1;
+            this.btnCancel.Text = "Cancel";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(324, 191);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 2;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // chkReadOnly
+            // 
+            this.chkReadOnly.AutoSize = true;
+            this.chkReadOnly.Location = new System.Drawing.Point(12, 195);
+            this.chkReadOnly.Name = "chkReadOnly";
+            this.chkReadOnly.Size = new System.Drawing.Size(76, 17);
+            this.chkReadOnly.TabIndex = 3;
+            this.chkReadOnly.Text = "Read Only";
+            this.chkReadOnly.UseVisualStyleBackColor = true;
+            // 
+            // listPhysicalDisks
+            // 
+            this.listPhysicalDisks.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.columnVolume,
+            this.columnName,
+            this.columnType,
+            this.columnStatus,
+            this.columnSize});
+            this.listPhysicalDisks.FullRowSelect = true;
+            this.listPhysicalDisks.Location = new System.Drawing.Point(12, 12);
+            this.listPhysicalDisks.Name = "listPhysicalDisks";
+            this.listPhysicalDisks.Size = new System.Drawing.Size(468, 173);
+            this.listPhysicalDisks.TabIndex = 4;
+            this.listPhysicalDisks.UseCompatibleStateImageBehavior = false;
+            this.listPhysicalDisks.View = System.Windows.Forms.View.Details;
+            this.listPhysicalDisks.ColumnWidthChanging += new System.Windows.Forms.ColumnWidthChangingEventHandler(this.listPhysicalDisks_ColumnWidthChanging);
+            // 
+            // columnVolume
+            // 
+            this.columnVolume.Text = "Volume";
+            // 
+            // columnName
+            // 
+            this.columnName.Text = "Name";
+            this.columnName.Width = 150;
+            // 
+            // columnType
+            // 
+            this.columnType.Text = "Type";
+            this.columnType.Width = 134;
+            // 
+            // columnStatus
+            // 
+            this.columnStatus.Text = "Status";
+            // 
+            // columnSize
+            // 
+            this.columnSize.Text = "Size";
+            this.columnSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+            // 
+            // SelectVolumeForm
+            // 
+            this.AcceptButton = this.btnOK;
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+            this.CancelButton = this.btnCancel;
+            this.ClientSize = new System.Drawing.Size(494, 225);
+            this.Controls.Add(this.listPhysicalDisks);
+            this.Controls.Add(this.chkReadOnly);
+            this.Controls.Add(this.btnOK);
+            this.Controls.Add(this.btnCancel);
+            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(500, 250);
+            this.MinimumSize = new System.Drawing.Size(500, 250);
+            this.Name = "SelectVolumeForm";
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+            this.Text = "Select Volume";
+            this.Load += new System.EventHandler(this.SelectPhysicalDiskForm_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.CheckBox chkReadOnly;
+        private System.Windows.Forms.ListView listPhysicalDisks;
+        private System.Windows.Forms.ColumnHeader columnVolume;
+        private System.Windows.Forms.ColumnHeader columnName;
+        private System.Windows.Forms.ColumnHeader columnType;
+        private System.Windows.Forms.ColumnHeader columnStatus;
+        private System.Windows.Forms.ColumnHeader columnSize;
+    }
+}

+ 154 - 0
ISCSIConsole/Win32/SelectVolumeForm.cs

@@ -0,0 +1,154 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using DiskAccessLibrary;
+using DiskAccessLibrary.LogicalDiskManager;
+using Utilities;
+
+namespace ISCSIConsole
+{
+    public partial class SelectVolumeForm : Form
+    {
+        private Volume m_selectedVolume;
+        private bool m_isReadOnly;
+
+        public SelectVolumeForm()
+        {
+            InitializeComponent();
+        }
+
+        private void SelectPhysicalDiskForm_Load(object sender, EventArgs e)
+        {
+            List<Volume> volumes = WindowsVolumeHelper.GetVolumes();
+            for(int index = 0; index < volumes.Count; index++)
+            {
+                Volume volume = volumes[index];
+                string title = String.Format("Volume {0}", index);
+                string type = VolumeHelper.GetVolumeTypeString(volume);
+                string status = VolumeHelper.GetVolumeStatusString(volume);
+
+                ulong volumeID = 0;
+                string name = String.Empty;
+                if (volume is DynamicVolume)
+                {
+                    volumeID = ((DynamicVolume)volume).VolumeID;
+                    name = ((DynamicVolume)volume).Name;
+                }
+                else if (volume is GPTPartition)
+                {
+                    name = ((GPTPartition)volume).PartitionName;
+                }
+                ListViewItem item = new ListViewItem(title);
+                item.SubItems.Add(name);
+                item.SubItems.Add(type);
+                item.SubItems.Add(status);
+                item.SubItems.Add(FormattingHelper.GetStandardSizeString(volume.Size));
+                item.Tag = volume;
+                listPhysicalDisks.Items.Add(item);
+            }
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            if (listPhysicalDisks.SelectedItems.Count > 0)
+            {
+                Volume selectedVolume = (Volume)listPhysicalDisks.SelectedItems[0].Tag;
+                if (!chkReadOnly.Checked)
+                {
+                    Guid? volumeGuid = WindowsVolumeHelper.GetWindowsVolumeGuid(selectedVolume);
+                    if (Environment.OSVersion.Version.Major >= 6)
+                    {
+                        // Windows Vista / 7 enforce various limitations on direct write operations to volumes and disks.
+                        // We either have to take the disk(s) offline or use the OS volume handle for write operations.
+                        if (!volumeGuid.HasValue)
+                        {
+                            MessageBox.Show("The selected volume is not recognized by your operating system");
+                            return;
+                        }
+                        selectedVolume = new OperatingSystemVolume(volumeGuid.Value, selectedVolume.BytesPerSector, selectedVolume.Size, chkReadOnly.Checked);
+                    }
+
+                    bool isLocked = false;
+                    if (volumeGuid.HasValue)
+                    {
+                        isLocked = WindowsVolumeManager.ExclusiveLock(volumeGuid.Value);
+                    }
+                    if (!isLocked)
+                    {
+                        MessageBox.Show("Unable to lock the volume", "Error");
+                        return;
+                    }
+                }
+                m_selectedVolume = selectedVolume;
+                m_isReadOnly = chkReadOnly.Checked;
+                this.DialogResult = DialogResult.OK;
+                this.Close();
+            }
+            else
+            {
+                MessageBox.Show("No volume was selected", "Error");
+                return;
+            }
+        }
+
+        private IList<PhysicalDisk> GetVolumeDisks(Volume volume)
+        {
+            SortedList<int, PhysicalDisk> disks = new SortedList<int,PhysicalDisk>();
+            if (volume is DynamicVolume)
+            {
+                foreach (DiskExtent extent in ((DynamicVolume)volume).Extents)
+                {
+                    if (extent.Disk is PhysicalDisk)
+                    {
+                        PhysicalDisk disk = (PhysicalDisk)extent.Disk;
+                        if (!disks.ContainsKey(disk.PhysicalDiskIndex))
+                        {
+                            disks.Add(disk.PhysicalDiskIndex, disk);
+                        }
+                    }
+                }
+            }
+            else if (volume is Partition)
+            {
+                Partition partition = (Partition)volume;
+                if (partition.Disk is PhysicalDisk)
+                {
+                    PhysicalDisk disk = (PhysicalDisk)partition.Disk;
+                    disks.Add(disk.PhysicalDiskIndex, (PhysicalDisk)disk);
+                }
+            }
+            return disks.Values;
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            this.DialogResult = DialogResult.Cancel;
+            this.Close();
+        }
+
+        public Volume SelectedVolume
+        {
+            get
+            {
+                return m_selectedVolume;
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return m_isReadOnly;
+            }
+        }
+
+        private void listPhysicalDisks_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
+        {
+            e.NewWidth = ((ListView)sender).Columns[e.ColumnIndex].Width;
+            e.Cancel = true;
+        }
+    }
+}

File diff suppressed because it is too large
+ 6293 - 0
ISCSIConsole/Win32/SelectVolumeForm.resx