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

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.Collections.Generic;
 using System.IO;
@@ -10,17 +16,18 @@ namespace ISCSIConsole
     {
         private static FileStream m_logFile;
 
-        public static void OpenLogFile(string logFilePath)
+        public static bool OpenLogFile(string logFilePath)
         {
             try
             {
                 // 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.
                 m_logFile = new FileStream(logFilePath, FileMode.Append, FileAccess.Write, FileShare.Read, 0x1000, FileOptions.WriteThrough);
+                return true;
             }
             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.Collections.Generic;
 using System.IO;
-using System.Security.Principal;
-using System.Reflection;
 using System.Text;
-using DiskAccessLibrary.LogicalDiskManager;
-using DiskAccessLibrary;
-using Utilities;
+using System.Threading;
+using System.Windows.Forms;
 
 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)
         {
-            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
                 {
-                    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