diff --git a/DiskImager.Installer/DiskImager.Installer.vdproj b/DiskImager.Installer/DiskImager.Installer.vdproj index cc0f046..5d98b8f 100644 --- a/DiskImager.Installer/DiskImager.Installer.vdproj +++ b/DiskImager.Installer/DiskImager.Installer.vdproj @@ -229,15 +229,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:Disk Imager" - "ProductCode" = "8:{7AE7013F-7719-46F7-BA1E-77085FB0AC2A}" - "PackageCode" = "8:{8B82D457-AA37-4EE1-877E-1AE6DDEFC68E}" + "ProductCode" = "8:{775B32DE-D69B-4A1A-9262-EB55FDC5F9DA}" + "PackageCode" = "8:{16CF7871-0DE7-4129-AB80-F3FBD415C4AB}" "UpgradeCode" = "8:{A2F957D8-23F6-44DB-A22C-CCA8275E1FCE}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:FALSE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.1.1" + "ProductVersion" = "8:1.1.3" "Manufacturer" = "8:Dynamic Devices" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/DiskImager.sln b/DiskImager.sln index 5383257..539659f 100644 --- a/DiskImager.sln +++ b/DiskImager.sln @@ -55,7 +55,6 @@ Global {1B0F140A-DFA6-4693-9C09-FCB9E0B35189}.Debug|x86.ActiveCfg = Debug|x86 {1B0F140A-DFA6-4693-9C09-FCB9E0B35189}.Release|Any CPU.ActiveCfg = Release|x86 {1B0F140A-DFA6-4693-9C09-FCB9E0B35189}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {1B0F140A-DFA6-4693-9C09-FCB9E0B35189}.Release|Mixed Platforms.Build.0 = Release|x86 {1B0F140A-DFA6-4693-9C09-FCB9E0B35189}.Release|x86.ActiveCfg = Release|x86 {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0E7413FF-EB9E-4714-ACF2-BE3A6A7B2FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU diff --git a/DiskImager/Disk.cs b/DiskImager/Disk.cs index 66309cc..7b2b601 100644 --- a/DiskImager/Disk.cs +++ b/DiskImager/Disk.cs @@ -287,6 +287,80 @@ where zipEntry.IsFile return !errored; } + /// + /// Erase MBR of drive (allows us to then reinsert and it will reformat to full capacity) + /// + /// + /// + /// + /// + public bool EraseMBR(string driveLetter) + { + var isErrored = false; + + IsCancelling = false; + + var dtStart = DateTime.Now; + + // + // Get physical drive partition for logical partition + // + var physicalDrive = _diskAccess.GetPhysicalPathForLogicalPath(driveLetter); + if (string.IsNullOrEmpty(physicalDrive)) + { + LogMsg(@"Error: Couldn't map partition to physical drive"); + _diskAccess.UnlockDrive(); + return false; + } + + // + // Lock logical drive + // + var success = _diskAccess.LockDrive(driveLetter); + if (!success) + { + LogMsg(@"Failed to lock drive"); + return false; + } + + + // + // Get drive size + // + var driveSize = _diskAccess.GetDriveSize(physicalDrive); + if (driveSize <= 0) + { + LogMsg(@"Failed to get device size"); + _diskAccess.UnlockDrive(); + return false; + } + + // + // Open the physical drive + // + var physicalHandle = _diskAccess.Open(physicalDrive); + if (physicalHandle == null) + { + LogMsg(@"Failed to open physical drive"); + _diskAccess.UnlockDrive(); + return false; + } + + var zeroData = new byte[512]; + int wroteBytes; + if (_diskAccess.Write(zeroData, zeroData.Length, out wroteBytes) < 0) + { + LogMsg(@"Error writing data to drive: " + Marshal.GetHRForLastWin32Error()); + isErrored = true; + } + + _diskAccess.Close(); + + _diskAccess.UnlockDrive(); + + return !isErrored; + } + /// /// Read data direct from drive to file /// @@ -294,7 +368,7 @@ where zipEntry.IsFile /// /// /// - public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR) + public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR, long start, long length) { IsCancelling = false; @@ -351,8 +425,7 @@ public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType e var buffer = new byte[Globals.MaxBufferSize]; var offset = 0L; - - + using(var basefs = (Stream)new FileStream(fileName, FileMode.Create, FileAccess.Write)) { Stream fs; diff --git a/DiskImager/MainForm.Designer.cs b/DiskImager/MainForm.Designer.cs index 31c4a7a..0ce1e98 100644 --- a/DiskImager/MainForm.Designer.cs +++ b/DiskImager/MainForm.Designer.cs @@ -51,10 +51,17 @@ private void InitializeComponent() this.displayAllDrivesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.groupBoxTruncation = new System.Windows.Forms.GroupBox(); this.checkBoxUseMBR = new System.Windows.Forms.CheckBox(); + this.Advanced = new System.Windows.Forms.GroupBox(); + this.labelLength = new System.Windows.Forms.Label(); + this.labelStart = new System.Windows.Forms.Label(); + this.textBoxLength = new System.Windows.Forms.TextBox(); + this.textBoxStart = new System.Windows.Forms.TextBox(); + this.buttonEraseMBR = new System.Windows.Forms.Button(); this.statusStrip1.SuspendLayout(); this.groupBoxCompression.SuspendLayout(); this.menuStripMain.SuspendLayout(); this.groupBoxTruncation.SuspendLayout(); + this.Advanced.SuspendLayout(); this.SuspendLayout(); // // comboBoxDrives @@ -78,9 +85,9 @@ private void InitializeComponent() // // buttonRead // - this.buttonRead.Location = new System.Drawing.Point(12, 115); + this.buttonRead.Location = new System.Drawing.Point(15, 96); this.buttonRead.Name = "buttonRead"; - this.buttonRead.Size = new System.Drawing.Size(75, 23); + this.buttonRead.Size = new System.Drawing.Size(53, 23); this.buttonRead.TabIndex = 2; this.buttonRead.Text = "Read"; this.buttonRead.UseVisualStyleBackColor = true; @@ -88,9 +95,9 @@ private void InitializeComponent() // // buttonWrite // - this.buttonWrite.Location = new System.Drawing.Point(93, 115); + this.buttonWrite.Location = new System.Drawing.Point(74, 96); this.buttonWrite.Name = "buttonWrite"; - this.buttonWrite.Size = new System.Drawing.Size(75, 23); + this.buttonWrite.Size = new System.Drawing.Size(54, 23); this.buttonWrite.TabIndex = 3; this.buttonWrite.Text = "Write"; this.buttonWrite.UseVisualStyleBackColor = true; @@ -98,9 +105,9 @@ private void InitializeComponent() // // buttonExit // - this.buttonExit.Location = new System.Drawing.Point(255, 115); + this.buttonExit.Location = new System.Drawing.Point(270, 96); this.buttonExit.Name = "buttonExit"; - this.buttonExit.Size = new System.Drawing.Size(75, 23); + this.buttonExit.Size = new System.Drawing.Size(63, 23); this.buttonExit.TabIndex = 4; this.buttonExit.Text = "Exit"; this.buttonExit.UseVisualStyleBackColor = true; @@ -166,9 +173,9 @@ private void InitializeComponent() // buttonCancel // this.buttonCancel.Enabled = false; - this.buttonCancel.Location = new System.Drawing.Point(174, 115); + this.buttonCancel.Location = new System.Drawing.Point(216, 96); this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.Size = new System.Drawing.Size(48, 23); this.buttonCancel.TabIndex = 10; this.buttonCancel.Text = "Cancel"; this.buttonCancel.UseVisualStyleBackColor = true; @@ -279,11 +286,68 @@ private void InitializeComponent() this.checkBoxUseMBR.Text = "Use MBR partition sizes"; this.checkBoxUseMBR.UseVisualStyleBackColor = true; // + // Advanced + // + this.Advanced.Controls.Add(this.labelLength); + this.Advanced.Controls.Add(this.labelStart); + this.Advanced.Controls.Add(this.textBoxLength); + this.Advanced.Controls.Add(this.textBoxStart); + this.Advanced.Location = new System.Drawing.Point(12, 125); + this.Advanced.Name = "Advanced"; + this.Advanced.Size = new System.Drawing.Size(318, 74); + this.Advanced.TabIndex = 14; + this.Advanced.TabStop = false; + this.Advanced.Text = "Advanced"; + // + // labelLength + // + this.labelLength.AutoSize = true; + this.labelLength.Location = new System.Drawing.Point(16, 49); + this.labelLength.Name = "labelLength"; + this.labelLength.Size = new System.Drawing.Size(40, 13); + this.labelLength.TabIndex = 4; + this.labelLength.Text = "Length"; + // + // labelStart + // + this.labelStart.AutoSize = true; + this.labelStart.Location = new System.Drawing.Point(16, 22); + this.labelStart.Name = "labelStart"; + this.labelStart.Size = new System.Drawing.Size(29, 13); + this.labelStart.TabIndex = 3; + this.labelStart.Text = "Start"; + // + // textBoxLength + // + this.textBoxLength.Location = new System.Drawing.Point(84, 48); + this.textBoxLength.Name = "textBoxLength"; + this.textBoxLength.Size = new System.Drawing.Size(228, 20); + this.textBoxLength.TabIndex = 2; + // + // textBoxStart + // + this.textBoxStart.Location = new System.Drawing.Point(84, 19); + this.textBoxStart.Name = "textBoxStart"; + this.textBoxStart.Size = new System.Drawing.Size(228, 20); + this.textBoxStart.TabIndex = 1; + // + // buttonEraseMBR + // + this.buttonEraseMBR.Location = new System.Drawing.Point(134, 96); + this.buttonEraseMBR.Name = "buttonEraseMBR"; + this.buttonEraseMBR.Size = new System.Drawing.Size(76, 23); + this.buttonEraseMBR.TabIndex = 15; + this.buttonEraseMBR.Text = "Erase MBR"; + this.buttonEraseMBR.UseVisualStyleBackColor = true; + this.buttonEraseMBR.Click += new System.EventHandler(this.ButtonEraseMBRClick); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(605, 261); + this.Controls.Add(this.buttonEraseMBR); + this.Controls.Add(this.Advanced); this.Controls.Add(this.groupBoxTruncation); this.Controls.Add(this.groupBoxCompression); this.Controls.Add(this.buttonCancel); @@ -313,6 +377,8 @@ private void InitializeComponent() this.menuStripMain.PerformLayout(); this.groupBoxTruncation.ResumeLayout(false); this.groupBoxTruncation.PerformLayout(); + this.Advanced.ResumeLayout(false); + this.Advanced.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -343,6 +409,12 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem displayAllDrivesToolStripMenuItem; private System.Windows.Forms.GroupBox groupBoxTruncation; private System.Windows.Forms.CheckBox checkBoxUseMBR; + private System.Windows.Forms.GroupBox Advanced; + private System.Windows.Forms.Label labelLength; + private System.Windows.Forms.Label labelStart; + private System.Windows.Forms.TextBox textBoxLength; + private System.Windows.Forms.TextBox textBoxStart; + private System.Windows.Forms.Button buttonEraseMBR; } } diff --git a/DiskImager/MainForm.cs b/DiskImager/MainForm.cs index 509953d..e5c990d 100644 --- a/DiskImager/MainForm.cs +++ b/DiskImager/MainForm.cs @@ -31,7 +31,7 @@ public MainForm() MessageBoxEx.Owner = this.Handle; - toolStripStatusLabel1.Text = @"Initialised. Licensed under GPLv3. Use at own risk!"; + toolStripStatusLabel1.Text = @"Initialised. Licensed under GPLv3."; saveFileDialog1.OverwritePrompt = false; saveFileDialog1.Filter = @"Image Files (*.img,*.bin,*.sdcard)|*.img;*.bin;*.sdcard|Compressed Files (*.zip,*.gz,*tgz)|*.zip;*.gz;*.tgz|All files (*.*)|*.*"; @@ -169,7 +169,30 @@ private void ButtonReadClick(object sender, EventArgs e) try { - _disk.ReadDrive(drive, textBoxFileName.Text, _eCompType, checkBoxUseMBR.Checked); + var start = 0l; + + if(!string.IsNullOrEmpty(textBoxStart.Text)) + { + try + { + start = long.Parse(textBoxStart.Text); + } catch + { + } + } + + var length = 0l; + if(!string.IsNullOrEmpty(textBoxLength.Text)) + { + try + { + length = long.Parse(textBoxLength.Text); + } catch + { + } + } + + _disk.ReadDrive(drive, textBoxFileName.Text, _eCompType, checkBoxUseMBR.Checked, start, length); } catch(Exception ex) { toolStripStatusLabel1.Text = ex.Message; @@ -229,6 +252,31 @@ private void ButtonWriteClick(object sender, EventArgs e) EnableButtons(); } + private void ButtonEraseMBRClick(object sender, EventArgs e) + { + if (comboBoxDrives.SelectedIndex < 0) + return; + + var drive = (string)comboBoxDrives.SelectedItem; + + var success = false; + try + { + success = _disk.EraseMBR(drive); + } + catch (Exception ex) + { + success = false; + toolStripStatusLabel1.Text = ex.Message; + } + + if (!success && !_disk.IsCancelling) + MessageBoxEx.Show("Problem writing to disk. Is it write-protected?", "Write Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + else + MessageBoxEx.Show("MBR erased. Please remove and reinsert to format", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + /// /// Called to persist registry values on closure so we can remember things like last file used /// @@ -325,7 +373,8 @@ private void ChooseFile() return; textBoxFileName.Text = saveFileDialog1.FileName; - TextBoxFileNameTextChanged(this, null); + + TextBoxFileNameTextChanged(this, null); } private void TextBoxFileNameTextChanged(object sender, EventArgs e) @@ -426,6 +475,7 @@ private void DisableButtons(bool running) { buttonRead.Enabled = false; buttonWrite.Enabled = false; + buttonEraseMBR.Enabled = false; buttonExit.Enabled = !running; buttonCancel.Enabled = running; comboBoxDrives.Enabled = false; @@ -442,6 +492,7 @@ private void EnableButtons() { buttonRead.Enabled = true; buttonWrite.Enabled = true; + buttonEraseMBR.Enabled = true; buttonExit.Enabled = true; buttonCancel.Enabled = false; comboBoxDrives.Enabled = true; diff --git a/DiskImager/Properties/AssemblyInfo.cs b/DiskImager/Properties/AssemblyInfo.cs index 62b55e5..63b97f8 100644 --- a/DiskImager/Properties/AssemblyInfo.cs +++ b/DiskImager/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.1.*")] -[assembly: AssemblyFileVersion("1.1.1.0")] +[assembly: AssemblyVersion("1.1.3.*")] +[assembly: AssemblyFileVersion("1.1.3.0")] diff --git a/README.md b/README.md index c5397de..6c3367e 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,17 @@ This utility is a C#.NET implementation, and adds a couple of features I wanted - it also *might* be slightly faster when dealing with uncompressed read/write -*NOTE This application is under development and could possibly cause damage to your computer drive(s). We cannot take responsibility for any damage caused or losses incurred through use of this utility. Use at own risk!* +*NOTE This application could possibly cause damage to your computer drive(s). We cannot take responsibility for any damage caused or losses incurred through use of this utility. Use at own risk!* Credits: Inspired by the excellent Win32DiskImager. ChangeLog ========= +1.1.3 03/05/16 AJL Add button to erase MBR (allows us to then reformat the drive to full capacity) + +1.1.2 20/08/15 AJL Add support for writing partial files (start/length) + 1.1.1 02/03/14 AJL Minor fix to error message when source file not available 1.1.0 12/05/14 AJL Updated to use latest SharpZipLib as we were encountering (de-)compression errors with the previous version