mirror of
https://github.com/RomanBelkov/DiskImager.git
synced 2026-05-15 14:15:51 -06:00
Added support for reading and writing directly to compressed formats: .zip, .tgz, .gz, Cleanups
This commit is contained in:
parent
dfb7cb4383
commit
06944d09c8
10 changed files with 657 additions and 178 deletions
|
|
@ -62,6 +62,19 @@
|
|||
"PrerequisitesLocation" = "2:1"
|
||||
"Url" = "8:"
|
||||
"ComponentsUrl" = "8:"
|
||||
"Items"
|
||||
{
|
||||
"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.0,Profile=Client"
|
||||
{
|
||||
"Name" = "8:Microsoft .NET Framework 4 Client Profile (x86 and x64)"
|
||||
"ProductCode" = "8:.NETFramework,Version=v4.0,Profile=Client"
|
||||
}
|
||||
"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1"
|
||||
{
|
||||
"Name" = "8:Windows Installer 3.1"
|
||||
"ProductCode" = "8:Microsoft.Windows.Installer.3.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"Release"
|
||||
|
|
@ -86,6 +99,19 @@
|
|||
"PrerequisitesLocation" = "2:1"
|
||||
"Url" = "8:"
|
||||
"ComponentsUrl" = "8:"
|
||||
"Items"
|
||||
{
|
||||
"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.0,Profile=Client"
|
||||
{
|
||||
"Name" = "8:Microsoft .NET Framework 4 Client Profile (x86 and x64)"
|
||||
"ProductCode" = "8:.NETFramework,Version=v4.0,Profile=Client"
|
||||
}
|
||||
"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1"
|
||||
{
|
||||
"Name" = "8:Windows Installer 3.1"
|
||||
"ProductCode" = "8:Microsoft.Windows.Installer.3.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -203,15 +229,15 @@
|
|||
{
|
||||
"Name" = "8:Microsoft Visual Studio"
|
||||
"ProductName" = "8:Disk Imager"
|
||||
"ProductCode" = "8:{4B773E0E-8A61-4441-9E75-7D48A42C7581}"
|
||||
"PackageCode" = "8:{1346B501-A133-428C-9788-B6BD06B7B55B}"
|
||||
"ProductCode" = "8:{E986C6D0-49F6-4FA9-BA4E-C4B25069CB4E}"
|
||||
"PackageCode" = "8:{4D46D4A9-7CFC-46C6-9539-5C2365A79E66}"
|
||||
"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.0.1"
|
||||
"ProductVersion" = "8:1.0.2"
|
||||
"Manufacturer" = "8:Dynamic Devices"
|
||||
"ARPHELPTELEPHONE" = "8:"
|
||||
"ARPHELPLINK" = "8:"
|
||||
|
|
@ -779,6 +805,34 @@
|
|||
{
|
||||
}
|
||||
}
|
||||
"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_9B462EF766884DF9B8B000AB7F833D6D"
|
||||
{
|
||||
"SourcePath" = "8:"
|
||||
"TargetName" = "8:"
|
||||
"Tag" = "8:"
|
||||
"Folder" = "8:_072AE4B10D3C471AA2B16D68E3691837"
|
||||
"Condition" = "8:"
|
||||
"Transitive" = "11:FALSE"
|
||||
"Vital" = "11:TRUE"
|
||||
"ReadOnly" = "11:FALSE"
|
||||
"Hidden" = "11:FALSE"
|
||||
"System" = "11:FALSE"
|
||||
"Permanent" = "11:FALSE"
|
||||
"SharedLegacy" = "11:FALSE"
|
||||
"PackageAs" = "3:1"
|
||||
"Register" = "3:1"
|
||||
"Exclude" = "11:FALSE"
|
||||
"IsDependency" = "11:FALSE"
|
||||
"IsolateTo" = "8:"
|
||||
"ProjectOutputGroupRegister" = "3:1"
|
||||
"OutputConfiguration" = "8:"
|
||||
"OutputGroupCanonicalName" = "8:ContentFiles"
|
||||
"OutputProjectGuid" = "8:{4A73C63C-2BF2-4F85-AA55-A5CA581A33B4}"
|
||||
"ShowKeyOutput" = "11:TRUE"
|
||||
"ExcludeFilters"
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Runtime.InteropServices;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using ICSharpCode.SharpZipLib.Tar;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace DynamicDevices.DiskWriter
|
||||
|
|
@ -23,12 +27,12 @@ namespace DynamicDevices.DiskWriter
|
|||
/// </summary>
|
||||
/// <param name="driveLetter"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="eCompType"></param>
|
||||
/// <returns></returns>
|
||||
public bool WriteDrive(string driveLetter, string fileName)
|
||||
public bool WriteDrive(string driveLetter, string fileName, EnumCompressionType eCompType)
|
||||
{
|
||||
var success = false;
|
||||
int intOut;
|
||||
long driveSize = 0;
|
||||
|
||||
IsCancelling = false;
|
||||
|
||||
|
|
@ -52,45 +56,47 @@ namespace DynamicDevices.DiskWriter
|
|||
"\"} where assocclass=Win32_LogicalDiskToPartition");
|
||||
searcher = new ManagementObjectSearcher(scope, associators);
|
||||
var disks = searcher.Get();
|
||||
foreach (ManagementObject disk in disks)
|
||||
if (
|
||||
!(from ManagementObject disk in disks select (string) disk["deviceid"]).Any(
|
||||
thisDisk => thisDisk == driveLetter)) continue;
|
||||
diskIndex = (int)(UInt32)current["diskindex"]; ;
|
||||
|
||||
//
|
||||
// Unmount partition (Todo: Note that we currntly only handle unmounting of one partition, which is the usual case for SD Cards)
|
||||
//
|
||||
|
||||
//
|
||||
// Open the volume
|
||||
///
|
||||
partitionHandle = NativeMethods.CreateFile(@"\\.\" + driveLetter, NativeMethods.GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
|
||||
if (partitionHandle.IsInvalid)
|
||||
{
|
||||
var thisDisk = (string)disk["deviceid"];
|
||||
if (thisDisk == driveLetter)
|
||||
{
|
||||
// Grab physical drive and size
|
||||
diskIndex = (int)(UInt32)current["diskindex"]; ;
|
||||
OnLogMsg(this, @"Failed to open device");
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unmount partition (todo: Note that we currntly only handle unmounting of one partition, which is the usual case for SD Cards)
|
||||
partitionHandle = NativeMethods.CreateFile(@"\\.\" + driveLetter, NativeMethods.GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
|
||||
if (partitionHandle.IsInvalid)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to open device");
|
||||
// NativeMethods.CloseHandle(partitionHandle);
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// Lock it
|
||||
//
|
||||
success = NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to lock device");
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
success = NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to lock device");
|
||||
// NativeMethods.CloseHandle(partitionHandle);
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
success = NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Error dismounting volume: " + Marshal.GetHRForLastWin32Error());
|
||||
NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
// NativeMethods.CloseHandle(partitionHandle);
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Dismount it
|
||||
//
|
||||
success = NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Error dismounting volume: " + Marshal.GetHRForLastWin32Error());
|
||||
NativeMethods.DeviceIoControl(partitionHandle, NativeMethods.FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
partitionHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +110,9 @@ namespace DynamicDevices.DiskWriter
|
|||
|
||||
var physicalDrive = @"\\.\PhysicalDrive" + diskIndex;
|
||||
|
||||
//
|
||||
// Now that we've dismounted the logical volume mounted on the removable drive we can open up the physical disk to write
|
||||
//
|
||||
var diskHandle = NativeMethods.CreateFile(physicalDrive, NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
|
||||
if (diskHandle.IsInvalid)
|
||||
{
|
||||
|
|
@ -115,13 +124,12 @@ namespace DynamicDevices.DiskWriter
|
|||
// Get drive size (NOTE: that WMI and IOCTL_DISK_GET_DRIVE_GEOMETRY don't give us the right value so we do it this way)
|
||||
//
|
||||
|
||||
driveSize = GetDiskSize(diskHandle);
|
||||
var driveSize = GetDiskSize(diskHandle);
|
||||
|
||||
success = NativeMethods.DeviceIoControl(diskHandle, NativeMethods.FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to lock device");
|
||||
// NativeMethods.CloseHandle(diskHandle);
|
||||
diskHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -129,28 +137,128 @@ namespace DynamicDevices.DiskWriter
|
|||
var buffer = new byte[Globals.MaxBufferSize];
|
||||
long offset = 0;
|
||||
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
|
||||
using (var basefs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (var bw = new BinaryReader(fs))
|
||||
|
||||
Stream fs;
|
||||
|
||||
switch (eCompType)
|
||||
{
|
||||
case EnumCompressionType.Zip:
|
||||
{
|
||||
var zipFile = new ZipFile(basefs);
|
||||
|
||||
Stream zis = null;
|
||||
|
||||
foreach(ZipEntry zipEntry in zipFile)
|
||||
{
|
||||
if (!zipEntry.IsFile)
|
||||
continue;
|
||||
|
||||
zis = zipFile.GetInputStream(zipEntry);
|
||||
break;
|
||||
}
|
||||
|
||||
if(zis == null)
|
||||
{
|
||||
OnLogMsg(this, @"Error reading zip input stream");
|
||||
goto readfail2;
|
||||
}
|
||||
|
||||
fs = zis;
|
||||
}
|
||||
break;
|
||||
|
||||
case EnumCompressionType.Gzip:
|
||||
{
|
||||
var gzis = new GZipInputStream(basefs) {IsStreamOwner = true};
|
||||
|
||||
fs = gzis;
|
||||
}
|
||||
break;
|
||||
|
||||
case EnumCompressionType.Targzip:
|
||||
{
|
||||
var gzos = new GZipInputStream(basefs);
|
||||
gzos.IsStreamOwner = true;
|
||||
|
||||
var tis = new TarInputStream(gzos);
|
||||
|
||||
TarEntry tarEntry;
|
||||
do
|
||||
{
|
||||
tarEntry = tis.GetNextEntry();
|
||||
} while (tarEntry.IsDirectory);
|
||||
|
||||
fs = tis;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// No compression - direct to file stream
|
||||
fs = basefs;
|
||||
break;
|
||||
}
|
||||
|
||||
var bufferOffset = 0;
|
||||
|
||||
using (var br = new BinaryReader(fs))
|
||||
{
|
||||
while (offset < driveSize && !IsCancelling)
|
||||
{
|
||||
var readBytes = bw.Read(buffer, 0, buffer.Length);
|
||||
|
||||
// Note: There's a problem writing certain lengths to the underlying physical drive.
|
||||
// This appears when we try to read from a compressed stream as it gives us
|
||||
// "strange" lengths which then fail to be written via Writefile() so try to build
|
||||
// up a decent block of bytes here...
|
||||
int readBytes = 0;
|
||||
do
|
||||
{
|
||||
readBytes = br.Read(buffer, bufferOffset, buffer.Length - bufferOffset);
|
||||
bufferOffset += readBytes;
|
||||
} while (bufferOffset < Globals.MaxBufferSize && readBytes != 0);
|
||||
|
||||
int wroteBytes;
|
||||
var bytesToWrite = bufferOffset;
|
||||
var trailingBytes = 0;
|
||||
|
||||
if (NativeMethods.WriteFile(diskHandle, buffer, readBytes, out wroteBytes, IntPtr.Zero) < 0)
|
||||
// Assume that the underlying physical drive will at least accept powers of two!
|
||||
if(!IsPowerOfTwo((ulong)bufferOffset))
|
||||
{
|
||||
// Find highest bit (32-bit max)
|
||||
var highBit = 31;
|
||||
for (; ((bufferOffset & (1 << highBit)) == 0) && highBit >= 0; highBit--)
|
||||
;
|
||||
|
||||
// Work out trailing bytes after last power of two
|
||||
var lastPowerOf2 = 1 << highBit;
|
||||
|
||||
bytesToWrite = lastPowerOf2;
|
||||
trailingBytes = bufferOffset - lastPowerOf2;
|
||||
}
|
||||
|
||||
if (NativeMethods.WriteFile(diskHandle, buffer, bytesToWrite, out wroteBytes, IntPtr.Zero) < 0)
|
||||
{
|
||||
OnLogMsg(this, @"Error writing data to drive: " + Marshal.GetHRForLastWin32Error());
|
||||
goto readfail1;
|
||||
}
|
||||
|
||||
if (wroteBytes != readBytes)
|
||||
if (wroteBytes != bytesToWrite)
|
||||
{
|
||||
OnLogMsg(this, @"Error writing data to drive - past EOF?");
|
||||
goto readfail1;
|
||||
}
|
||||
|
||||
// Move trailing bytes up - Todo: Suboptimal
|
||||
if (trailingBytes > 0)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, bufferOffset - trailingBytes, buffer, 0, trailingBytes);
|
||||
bufferOffset = trailingBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferOffset = 0;
|
||||
}
|
||||
offset += (uint)wroteBytes;
|
||||
|
||||
var percentDone = (int)(100 * offset / driveSize);
|
||||
|
|
@ -166,23 +274,14 @@ namespace DynamicDevices.DiskWriter
|
|||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
readfail1:
|
||||
NativeMethods.DeviceIoControl(diskHandle, NativeMethods.FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
readfail2:
|
||||
if (diskHandle != null)
|
||||
{
|
||||
// NativeMethods.CloseHandle(diskHandle);
|
||||
diskHandle.Dispose();
|
||||
}
|
||||
readfail2:
|
||||
diskHandle.Dispose();
|
||||
readfail3:
|
||||
|
||||
if (partitionHandle != null)
|
||||
{
|
||||
// NativeMethods.CloseHandle(partitionHandle);
|
||||
partitionHandle.Dispose();
|
||||
}
|
||||
|
||||
var tstotalTime = DateTime.Now.Subtract(dtStart);
|
||||
|
||||
|
|
@ -199,12 +298,12 @@ namespace DynamicDevices.DiskWriter
|
|||
/// </summary>
|
||||
/// <param name="driveLetter"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="eCompType"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadDrive(string driveLetter, string fileName)
|
||||
public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType)
|
||||
{
|
||||
var success = false;
|
||||
int intOut;
|
||||
long driveSize = 0;
|
||||
|
||||
IsCancelling = false;
|
||||
|
||||
|
|
@ -235,11 +334,11 @@ namespace DynamicDevices.DiskWriter
|
|||
//
|
||||
// Get drive size (NOTE: that WMI and IOCTL_DISK_GET_DRIVE_GEOMETRY don't give us the right value so we do it this way)
|
||||
//
|
||||
driveSize = GetDiskSize(diskHandle);
|
||||
var driveSize = GetDiskSize(diskHandle);
|
||||
if(driveSize <= 0)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to get device size");
|
||||
NativeMethods.CloseHandle(diskHandle);
|
||||
diskHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +349,7 @@ namespace DynamicDevices.DiskWriter
|
|||
if (!success)
|
||||
{
|
||||
OnLogMsg(this, @"Failed to lock device");
|
||||
NativeMethods.CloseHandle(diskHandle);
|
||||
diskHandle.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -261,8 +360,75 @@ namespace DynamicDevices.DiskWriter
|
|||
var buffer = new byte[Globals.MaxBufferSize];
|
||||
var offset = 0L;
|
||||
|
||||
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
|
||||
|
||||
using(var basefs = (Stream)new FileStream(fileName, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
Stream fs;
|
||||
|
||||
switch (eCompType)
|
||||
{
|
||||
case EnumCompressionType.Zip:
|
||||
{
|
||||
var zfs = new ZipOutputStream(basefs);
|
||||
|
||||
// Default to middle of the range compression
|
||||
zfs.SetLevel(Globals.CompressionLevel);
|
||||
|
||||
var fi = new FileInfo(fileName);
|
||||
var entryName = fi.Name;
|
||||
entryName = entryName.ToLower().Replace(".zip", "");
|
||||
entryName = ZipEntry.CleanName(entryName);
|
||||
var zipEntry = new ZipEntry(entryName) {DateTime = fi.LastWriteTime};
|
||||
zfs.IsStreamOwner = true;
|
||||
|
||||
// Todo: Consider whether size needs setting for older utils ?
|
||||
|
||||
zfs.PutNextEntry(zipEntry);
|
||||
|
||||
fs = zfs;
|
||||
}
|
||||
break;
|
||||
|
||||
case EnumCompressionType.Gzip:
|
||||
{
|
||||
var gzos = new GZipOutputStream(basefs);
|
||||
gzos.SetLevel(Globals.CompressionLevel);
|
||||
gzos.IsStreamOwner = true;
|
||||
|
||||
fs = gzos;
|
||||
}
|
||||
break;
|
||||
|
||||
case EnumCompressionType.Targzip:
|
||||
{
|
||||
var gzos = new GZipOutputStream(basefs);
|
||||
gzos.SetLevel(Globals.CompressionLevel);
|
||||
gzos.IsStreamOwner = true;
|
||||
|
||||
var tos = new TarOutputStream(gzos);
|
||||
|
||||
var fi = new FileInfo(fileName);
|
||||
var entryName = fi.Name;
|
||||
entryName = entryName.ToLower().Replace(".tar.gz", "");
|
||||
entryName = entryName.ToLower().Replace(".tgz", "");
|
||||
|
||||
var tarEntry = TarEntry.CreateTarEntry(entryName);
|
||||
tarEntry.Size = driveSize;
|
||||
tarEntry.ModTime = DateTime.SpecifyKind(fi.LastWriteTime, DateTimeKind.Utc);
|
||||
|
||||
tos.PutNextEntry(tarEntry);
|
||||
|
||||
fs = tos;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// No compression - direct to file stream
|
||||
fs = basefs;
|
||||
break;
|
||||
}
|
||||
|
||||
using (var bw = new BinaryWriter(fs))
|
||||
{
|
||||
while (offset < driveSize && !IsCancelling)
|
||||
|
|
@ -271,13 +437,17 @@ namespace DynamicDevices.DiskWriter
|
|||
// seem to do a partial read. Deal with this by reading the remaining bytes at the end of the
|
||||
// drive if necessary
|
||||
|
||||
var readMaxLength = (int)((((ulong)driveSize - (ulong)offset) < (ulong)buffer.Length) ? ((ulong)driveSize - (ulong)offset) : (ulong)buffer.Length);
|
||||
var readMaxLength =
|
||||
(int)
|
||||
((((ulong) driveSize - (ulong) offset) < (ulong) buffer.Length)
|
||||
? ((ulong) driveSize - (ulong) offset)
|
||||
: (ulong) buffer.Length);
|
||||
|
||||
int readBytes;
|
||||
if (NativeMethods.ReadFile(diskHandle, buffer, readMaxLength, out readBytes, IntPtr.Zero) < 0)
|
||||
{
|
||||
OnLogMsg(this, @"Error reading data from drive: " +
|
||||
Marshal.GetHRForLastWin32Error());
|
||||
Marshal.GetHRForLastWin32Error());
|
||||
goto readfail1;
|
||||
}
|
||||
|
||||
|
|
@ -290,27 +460,32 @@ namespace DynamicDevices.DiskWriter
|
|||
goto readfail1;
|
||||
}
|
||||
|
||||
offset += (uint)readBytes;
|
||||
offset += (uint) readBytes;
|
||||
|
||||
var percentDone = (int)(100 * offset / driveSize);
|
||||
var percentDone = (int) (100*offset/driveSize);
|
||||
var tsElapsed = DateTime.Now.Subtract(dtStart);
|
||||
var bytesPerSec = offset / tsElapsed.TotalSeconds;
|
||||
var bytesPerSec = offset/tsElapsed.TotalSeconds;
|
||||
|
||||
OnProgress(this, percentDone);
|
||||
OnLogMsg(this, @"Read " + percentDone + @"%, " + (offset / (1024 * 1024)) + @" MB / " +
|
||||
(driveSize / (1024 * 1024) + " MB, " +
|
||||
string.Format("{0:F}", (bytesPerSec / (1024 * 1024))) + @" MB/sec, Elapsed time: " + tsElapsed.ToString(@"dd\.hh\:mm\:ss")));
|
||||
OnLogMsg(this, @"Read " + percentDone + @"%, " + (offset/(1024*1024)) + @" MB / " +
|
||||
(driveSize/(1024*1024) + " MB, " +
|
||||
string.Format("{0:F}", (bytesPerSec/(1024*1024))) + @" MB/sec, Elapsed time: " +
|
||||
tsElapsed.ToString(@"dd\.hh\:mm\:ss")));
|
||||
|
||||
}
|
||||
|
||||
// Todo: Do we need this?
|
||||
if(fs is ZipOutputStream)
|
||||
((ZipOutputStream)fs).CloseEntry();
|
||||
if(fs is TarOutputStream)
|
||||
((TarOutputStream)fs).CloseEntry();
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
readfail1:
|
||||
NativeMethods.DeviceIoControl(diskHandle, NativeMethods.FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
|
||||
readfail2:
|
||||
// NativeMethods.CloseHandle(diskHandle);
|
||||
diskHandle.Dispose();
|
||||
readfail3:
|
||||
var tstotalTime = DateTime.Now.Subtract(dtStart);
|
||||
|
|
@ -330,7 +505,7 @@ namespace DynamicDevices.DiskWriter
|
|||
/// </summary>
|
||||
/// <param name="driveLetter"></param>
|
||||
/// <returns></returns>
|
||||
private int GetDiskIndex(string driveLetter)
|
||||
private static int GetDiskIndex(string driveLetter)
|
||||
{
|
||||
int diskIndex = -1;
|
||||
|
||||
|
|
@ -346,16 +521,10 @@ namespace DynamicDevices.DiskWriter
|
|||
"\"} where assocclass=Win32_LogicalDiskToPartition");
|
||||
searcher = new ManagementObjectSearcher(scope, associators);
|
||||
var disks = searcher.Get();
|
||||
foreach (ManagementObject disk in disks)
|
||||
{
|
||||
var thisDisk = (string)disk["deviceid"];
|
||||
if (thisDisk == driveLetter)
|
||||
{
|
||||
// Grab physical drive and size
|
||||
diskIndex = (int)(UInt32)current["diskindex"]; ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (
|
||||
!(from ManagementObject disk in disks select (string) disk["deviceid"]).Any(
|
||||
thisDisk => thisDisk == driveLetter)) continue;
|
||||
diskIndex = (int)(UInt32)current["diskindex"];
|
||||
}
|
||||
|
||||
return diskIndex;
|
||||
|
|
@ -366,7 +535,7 @@ namespace DynamicDevices.DiskWriter
|
|||
/// </summary>
|
||||
/// <param name="diskHandle"></param>
|
||||
/// <returns></returns>
|
||||
private long GetDiskSize(SafeFileHandle diskHandle)
|
||||
private static long GetDiskSize(SafeFileHandle diskHandle)
|
||||
{
|
||||
long size = -1;
|
||||
|
||||
|
|
@ -387,6 +556,11 @@ namespace DynamicDevices.DiskWriter
|
|||
return size;
|
||||
}
|
||||
|
||||
bool IsPowerOfTwo(ulong x)
|
||||
{
|
||||
return (x != 0) && ((x & (x - 1)) == 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
|
@ -13,6 +13,21 @@
|
|||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
|
|
@ -42,6 +57,13 @@
|
|||
<PropertyGroup>
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SharpZipLib">
|
||||
<HintPath>..\Libs\SharpZipLib\SharpZipLib.dll</HintPath>
|
||||
|
|
@ -61,6 +83,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Disk.cs" />
|
||||
<Compile Include="DiskGeometry.cs" />
|
||||
<Compile Include="Enumerations.cs" />
|
||||
<Compile Include="Globals.cs" />
|
||||
<Compile Include="MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
|
@ -99,6 +122,28 @@
|
|||
<ItemGroup>
|
||||
<Content Include="DD-All.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\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.
|
||||
|
|
@ -115,7 +160,7 @@
|
|||
<MergeAsm Include="$(OutputPath)SharpZipLib.dll" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MergedAssembly>$(ProjectDir)$(OutDir)$(TargetFileName)</MergedAssembly>
|
||||
<MergedAssembly>$(ProjectDir)$(OutDir)DiskImager-merged.exe</MergedAssembly>
|
||||
</PropertyGroup>
|
||||
<Message Text="ILMerge @(MergeAsm) -> $(MergedAssembly)" Importance="high" />
|
||||
<ILMerge InputAssemblies="@(MergeAsm)" OutputFile="$(MergedAssembly)" TargetKind="SameAsPrimaryAssembly" />
|
||||
|
|
|
|||
11
DiskImager/Enumerations.cs
Normal file
11
DiskImager/Enumerations.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
namespace DynamicDevices.DiskWriter
|
||||
{
|
||||
public enum EnumCompressionType
|
||||
{
|
||||
None = 0,
|
||||
Zip = 1,
|
||||
Gzip = 2,
|
||||
Targzip = 3
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace DynamicDevices.DiskWriter
|
||||
namespace DynamicDevices.DiskWriter
|
||||
{
|
||||
internal class Globals
|
||||
{
|
||||
private const int MAX_BUFFER_SIZE = 1 * 1024 * 1024;
|
||||
private const int DEFAULT_COMPRESSION_LEVEL = 3;
|
||||
|
||||
private static int _maxBufferSize = MAX_BUFFER_SIZE;
|
||||
private static int _compressionLevel = DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
public static int MaxBufferSize { get { return _maxBufferSize; } set { _maxBufferSize = value; } }
|
||||
|
||||
public static int CompressionLevel { get { return _compressionLevel; } set { _compressionLevel = value; } }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
107
DiskImager/MainForm.Designer.cs
generated
107
DiskImager/MainForm.Designer.cs
generated
|
|
@ -36,14 +36,18 @@
|
|||
this.buttonChooseFile = new System.Windows.Forms.Button();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
|
||||
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
|
||||
this.labelFileName = new System.Windows.Forms.Label();
|
||||
this.labelDriveTitle = new System.Windows.Forms.Label();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
this.labelSize = new System.Windows.Forms.Label();
|
||||
this.groupBoxCompression = new System.Windows.Forms.GroupBox();
|
||||
this.radioButtonCompNone = new System.Windows.Forms.RadioButton();
|
||||
this.radioButtonCompTgz = new System.Windows.Forms.RadioButton();
|
||||
this.radioButtonCompGz = new System.Windows.Forms.RadioButton();
|
||||
this.radioButtonCompZip = new System.Windows.Forms.RadioButton();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.groupBoxCompression.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// comboBoxDrives
|
||||
|
|
@ -56,7 +60,6 @@
|
|||
this.comboBoxDrives.Name = "comboBoxDrives";
|
||||
this.comboBoxDrives.Size = new System.Drawing.Size(121, 21);
|
||||
this.comboBoxDrives.TabIndex = 0;
|
||||
this.comboBoxDrives.SelectedIndexChanged += new System.EventHandler(this.ComboBoxDrivesSelectedIndexChanged);
|
||||
//
|
||||
// textBoxFileName
|
||||
//
|
||||
|
|
@ -64,10 +67,11 @@
|
|||
this.textBoxFileName.Name = "textBoxFileName";
|
||||
this.textBoxFileName.Size = new System.Drawing.Size(420, 20);
|
||||
this.textBoxFileName.TabIndex = 1;
|
||||
this.textBoxFileName.TextChanged += new System.EventHandler(this.TextBoxFileNameTextChanged);
|
||||
//
|
||||
// buttonRead
|
||||
//
|
||||
this.buttonRead.Location = new System.Drawing.Point(12, 71);
|
||||
this.buttonRead.Location = new System.Drawing.Point(12, 84);
|
||||
this.buttonRead.Name = "buttonRead";
|
||||
this.buttonRead.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonRead.TabIndex = 2;
|
||||
|
|
@ -77,7 +81,7 @@
|
|||
//
|
||||
// buttonWrite
|
||||
//
|
||||
this.buttonWrite.Location = new System.Drawing.Point(93, 71);
|
||||
this.buttonWrite.Location = new System.Drawing.Point(93, 84);
|
||||
this.buttonWrite.Name = "buttonWrite";
|
||||
this.buttonWrite.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonWrite.TabIndex = 3;
|
||||
|
|
@ -87,7 +91,7 @@
|
|||
//
|
||||
// buttonExit
|
||||
//
|
||||
this.buttonExit.Location = new System.Drawing.Point(255, 71);
|
||||
this.buttonExit.Location = new System.Drawing.Point(255, 84);
|
||||
this.buttonExit.Name = "buttonExit";
|
||||
this.buttonExit.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonExit.TabIndex = 4;
|
||||
|
|
@ -109,7 +113,7 @@
|
|||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripStatusLabel1});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 137);
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 155);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(600, 22);
|
||||
this.statusStrip1.TabIndex = 6;
|
||||
|
|
@ -121,11 +125,6 @@
|
|||
this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17);
|
||||
this.toolStripStatusLabel1.Text = "toolStripStatusLabel1";
|
||||
//
|
||||
// openFileDialog1
|
||||
//
|
||||
this.openFileDialog1.DefaultExt = "img";
|
||||
this.openFileDialog1.Filter = "Image Files (*.img)|*.img|Binary files (*.bin)|*.bin|All files (*.*)|*.*";
|
||||
//
|
||||
// saveFileDialog1
|
||||
//
|
||||
this.saveFileDialog1.DefaultExt = "img";
|
||||
|
|
@ -151,7 +150,7 @@
|
|||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Location = new System.Drawing.Point(12, 109);
|
||||
this.progressBar1.Location = new System.Drawing.Point(12, 132);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(578, 10);
|
||||
this.progressBar1.TabIndex = 9;
|
||||
|
|
@ -159,7 +158,7 @@
|
|||
// buttonCancel
|
||||
//
|
||||
this.buttonCancel.Enabled = false;
|
||||
this.buttonCancel.Location = new System.Drawing.Point(174, 71);
|
||||
this.buttonCancel.Location = new System.Drawing.Point(174, 84);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.buttonCancel.TabIndex = 10;
|
||||
|
|
@ -167,22 +166,71 @@
|
|||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick);
|
||||
//
|
||||
// labelSize
|
||||
// groupBoxCompression
|
||||
//
|
||||
this.labelSize.AutoSize = true;
|
||||
this.labelSize.Location = new System.Drawing.Point(475, 58);
|
||||
this.labelSize.Name = "labelSize";
|
||||
this.labelSize.Size = new System.Drawing.Size(35, 13);
|
||||
this.labelSize.TabIndex = 11;
|
||||
this.labelSize.Text = "label1";
|
||||
this.labelSize.Visible = false;
|
||||
this.groupBoxCompression.Controls.Add(this.radioButtonCompNone);
|
||||
this.groupBoxCompression.Controls.Add(this.radioButtonCompTgz);
|
||||
this.groupBoxCompression.Controls.Add(this.radioButtonCompGz);
|
||||
this.groupBoxCompression.Controls.Add(this.radioButtonCompZip);
|
||||
this.groupBoxCompression.Location = new System.Drawing.Point(336, 71);
|
||||
this.groupBoxCompression.Name = "groupBoxCompression";
|
||||
this.groupBoxCompression.Size = new System.Drawing.Size(252, 49);
|
||||
this.groupBoxCompression.TabIndex = 11;
|
||||
this.groupBoxCompression.TabStop = false;
|
||||
this.groupBoxCompression.Text = "Compression";
|
||||
//
|
||||
// radioButtonCompNone
|
||||
//
|
||||
this.radioButtonCompNone.AutoSize = true;
|
||||
this.radioButtonCompNone.Checked = true;
|
||||
this.radioButtonCompNone.Location = new System.Drawing.Point(170, 19);
|
||||
this.radioButtonCompNone.Name = "radioButtonCompNone";
|
||||
this.radioButtonCompNone.Size = new System.Drawing.Size(56, 17);
|
||||
this.radioButtonCompNone.TabIndex = 3;
|
||||
this.radioButtonCompNone.TabStop = true;
|
||||
this.radioButtonCompNone.Text = "NONE";
|
||||
this.radioButtonCompNone.UseVisualStyleBackColor = true;
|
||||
this.radioButtonCompNone.CheckedChanged += new System.EventHandler(this.RadioButtonCompNoneCheckedChanged);
|
||||
//
|
||||
// radioButtonCompTgz
|
||||
//
|
||||
this.radioButtonCompTgz.AutoSize = true;
|
||||
this.radioButtonCompTgz.Location = new System.Drawing.Point(117, 19);
|
||||
this.radioButtonCompTgz.Name = "radioButtonCompTgz";
|
||||
this.radioButtonCompTgz.Size = new System.Drawing.Size(47, 17);
|
||||
this.radioButtonCompTgz.TabIndex = 2;
|
||||
this.radioButtonCompTgz.Text = "TGZ";
|
||||
this.radioButtonCompTgz.UseVisualStyleBackColor = true;
|
||||
this.radioButtonCompTgz.CheckedChanged += new System.EventHandler(this.RadioButtonCompTgzCheckedChanged);
|
||||
//
|
||||
// radioButtonCompGz
|
||||
//
|
||||
this.radioButtonCompGz.AutoSize = true;
|
||||
this.radioButtonCompGz.Location = new System.Drawing.Point(71, 19);
|
||||
this.radioButtonCompGz.Name = "radioButtonCompGz";
|
||||
this.radioButtonCompGz.Size = new System.Drawing.Size(40, 17);
|
||||
this.radioButtonCompGz.TabIndex = 1;
|
||||
this.radioButtonCompGz.Text = "GZ";
|
||||
this.radioButtonCompGz.UseVisualStyleBackColor = true;
|
||||
this.radioButtonCompGz.CheckedChanged += new System.EventHandler(this.RadioButtonCompGzCheckedChanged);
|
||||
//
|
||||
// radioButtonCompZip
|
||||
//
|
||||
this.radioButtonCompZip.AutoSize = true;
|
||||
this.radioButtonCompZip.Location = new System.Drawing.Point(23, 19);
|
||||
this.radioButtonCompZip.Name = "radioButtonCompZip";
|
||||
this.radioButtonCompZip.Size = new System.Drawing.Size(42, 17);
|
||||
this.radioButtonCompZip.TabIndex = 0;
|
||||
this.radioButtonCompZip.Text = "ZIP";
|
||||
this.radioButtonCompZip.UseVisualStyleBackColor = true;
|
||||
this.radioButtonCompZip.CheckedChanged += new System.EventHandler(this.RadioButtonCompZipCheckedChanged);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(600, 159);
|
||||
this.Controls.Add(this.labelSize);
|
||||
this.ClientSize = new System.Drawing.Size(600, 177);
|
||||
this.Controls.Add(this.groupBoxCompression);
|
||||
this.Controls.Add(this.buttonCancel);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.Controls.Add(this.labelDriveTitle);
|
||||
|
|
@ -195,11 +243,15 @@
|
|||
this.Controls.Add(this.textBoxFileName);
|
||||
this.Controls.Add(this.comboBoxDrives);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "MainForm";
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.Text = "Disk Imager";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainFormFormClosing);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.groupBoxCompression.ResumeLayout(false);
|
||||
this.groupBoxCompression.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
|
@ -215,13 +267,16 @@
|
|||
private System.Windows.Forms.Button buttonChooseFile;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
|
||||
private System.Windows.Forms.OpenFileDialog openFileDialog1;
|
||||
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
|
||||
private System.Windows.Forms.Label labelFileName;
|
||||
private System.Windows.Forms.Label labelDriveTitle;
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private System.Windows.Forms.Button buttonCancel;
|
||||
private System.Windows.Forms.Label labelSize;
|
||||
private System.Windows.Forms.GroupBox groupBoxCompression;
|
||||
private System.Windows.Forms.RadioButton radioButtonCompNone;
|
||||
private System.Windows.Forms.RadioButton radioButtonCompTgz;
|
||||
private System.Windows.Forms.RadioButton radioButtonCompGz;
|
||||
private System.Windows.Forms.RadioButton radioButtonCompZip;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,16 +9,27 @@ namespace DynamicDevices.DiskWriter
|
|||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly ManagementEventWatcher _watcher = new ManagementEventWatcher();
|
||||
|
||||
private readonly Disk _disk;
|
||||
|
||||
private EnumCompressionType _eCompType;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
toolStripStatusLabel1.Text = @"OK";
|
||||
|
||||
saveFileDialog1.OverwritePrompt = false;
|
||||
saveFileDialog1.Filter = @"Image Files (*.img,*.bin,*.sdcard)|*.img;*.bin;*.sdcard|Compressed Files (*.zip,*.gz,*tgz)|*.zip;*.gz;*.tgz|All files (*.*)|*.*";
|
||||
|
||||
// Set version into title
|
||||
var version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
Text += @" v" + version;
|
||||
|
|
@ -49,6 +60,10 @@ namespace DynamicDevices.DiskWriter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Globals.CompressionLevel = (int)key.GetValue("CompressionLevel", Globals.CompressionLevel);
|
||||
Globals.MaxBufferSize = (int)key.GetValue("MaxBufferSize", Globals.MaxBufferSize);
|
||||
|
||||
key.Close();
|
||||
}
|
||||
|
||||
|
|
@ -64,17 +79,7 @@ namespace DynamicDevices.DiskWriter
|
|||
_watcher.Start();
|
||||
}
|
||||
|
||||
void _disk_OnProgress(object sender, int progressPercentage)
|
||||
{
|
||||
progressBar1.Value = progressPercentage;
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
void _disk_OnLogMsg(object sender, string message)
|
||||
{
|
||||
toolStripStatusLabel1.Text = message;
|
||||
Application.DoEvents();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override sealed string Text
|
||||
{
|
||||
|
|
@ -82,24 +87,60 @@ namespace DynamicDevices.DiskWriter
|
|||
set { base.Text = value; }
|
||||
}
|
||||
|
||||
#region Disk access event handlers
|
||||
|
||||
/// <summary>
|
||||
/// Called to update progress bar as we read/write disk
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="progressPercentage"></param>
|
||||
void _disk_OnProgress(object sender, int progressPercentage)
|
||||
{
|
||||
progressBar1.Value = progressPercentage;
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to display/log messages from disk handling
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="message"></param>
|
||||
void _disk_OnLogMsg(object sender, string message)
|
||||
{
|
||||
toolStripStatusLabel1.Text = message;
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI Handling
|
||||
|
||||
/// <summary>
|
||||
/// Close the application
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonExitClick(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a file for read/write from/to removable media
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonChooseFileClick(object sender, EventArgs e)
|
||||
{
|
||||
saveFileDialog1.OverwritePrompt = false;
|
||||
|
||||
var dr = saveFileDialog1.ShowDialog();
|
||||
if (dr != DialogResult.OK)
|
||||
return;
|
||||
|
||||
textBoxFileName.Text = saveFileDialog1.FileName;
|
||||
ChooseFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from removable media to file
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonReadClick(object sender, EventArgs e)
|
||||
{
|
||||
if (comboBoxDrives.SelectedIndex < 0)
|
||||
|
|
@ -108,19 +149,13 @@ namespace DynamicDevices.DiskWriter
|
|||
var drive = (string)comboBoxDrives.SelectedItem;
|
||||
|
||||
if(string.IsNullOrEmpty(textBoxFileName.Text))
|
||||
{
|
||||
var dr = saveFileDialog1.ShowDialog();
|
||||
if (dr != DialogResult.OK)
|
||||
return;
|
||||
|
||||
textBoxFileName.Text = saveFileDialog1.FileName;
|
||||
}
|
||||
ChooseFile();
|
||||
|
||||
DisableButtons(true);
|
||||
|
||||
try
|
||||
{
|
||||
_disk.ReadDrive(drive, textBoxFileName.Text);
|
||||
_disk.ReadDrive(drive, textBoxFileName.Text, _eCompType);
|
||||
} catch(Exception ex)
|
||||
{
|
||||
toolStripStatusLabel1.Text = ex.Message;
|
||||
|
|
@ -129,6 +164,11 @@ namespace DynamicDevices.DiskWriter
|
|||
EnableButtons();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write to removable media from file
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonWriteClick(object sender, EventArgs e)
|
||||
{
|
||||
if (comboBoxDrives.SelectedIndex < 0)
|
||||
|
|
@ -137,19 +177,13 @@ namespace DynamicDevices.DiskWriter
|
|||
var drive = (string)comboBoxDrives.SelectedItem;
|
||||
|
||||
if (string.IsNullOrEmpty(textBoxFileName.Text))
|
||||
{
|
||||
var dr = openFileDialog1.ShowDialog();
|
||||
if (dr != DialogResult.OK)
|
||||
return;
|
||||
|
||||
textBoxFileName.Text = openFileDialog1.FileName;
|
||||
}
|
||||
ChooseFile();
|
||||
|
||||
DisableButtons(true);
|
||||
|
||||
try
|
||||
{
|
||||
_disk.WriteDrive(drive, textBoxFileName.Text);
|
||||
_disk.WriteDrive(drive, textBoxFileName.Text, _eCompType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -159,6 +193,11 @@ namespace DynamicDevices.DiskWriter
|
|||
EnableButtons();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to persist registry values on closure so we can remember things like last file used
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void MainFormFormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
var key = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Dynamic Devices Ltd\\DiskImager");
|
||||
|
|
@ -171,33 +210,106 @@ namespace DynamicDevices.DiskWriter
|
|||
_watcher.Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels an ongoing read/write
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ButtonCancelClick(object sender, EventArgs e)
|
||||
{
|
||||
_disk.IsCancelling = true;
|
||||
}
|
||||
|
||||
private void ComboBoxDrivesSelectedIndexChanged(object sender, EventArgs e)
|
||||
private void RadioButtonCompZipCheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
labelSize.Text = "";
|
||||
UpdateFileNameText();
|
||||
}
|
||||
|
||||
if(comboBoxDrives.SelectedIndex >= 0)
|
||||
{
|
||||
foreach (var drive in DriveInfo.GetDrives())
|
||||
{
|
||||
// Only display removable drives
|
||||
if (drive.DriveType == DriveType.Removable)
|
||||
{
|
||||
if (drive.Name == comboBoxDrives.SelectedItem + "\\")
|
||||
labelSize.Text = @"Size: " + (drive.TotalSize/(1024*1024)) + @" MB";
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RadioButtonCompTgzCheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateFileNameText();
|
||||
}
|
||||
|
||||
private void RadioButtonCompGzCheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateFileNameText();
|
||||
}
|
||||
|
||||
private void RadioButtonCompNoneCheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateFileNameText();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation
|
||||
|
||||
private void UpdateFileNameText()
|
||||
{
|
||||
var text = textBoxFileName.Text;
|
||||
text = text.Replace(".tar.gz", "");
|
||||
text = text.Replace(".tgz", "");
|
||||
text = text.Replace(".tar", "");
|
||||
text = text.Replace(".gzip", "");
|
||||
text = text.Replace(".gz", "");
|
||||
text = text.Replace(".zip", "");
|
||||
|
||||
if (radioButtonCompNone.Checked)
|
||||
{
|
||||
textBoxFileName.Text = text;
|
||||
} else if(radioButtonCompZip.Checked)
|
||||
{
|
||||
text += ".zip";
|
||||
textBoxFileName.Text = text;
|
||||
} else if(radioButtonCompTgz.Checked)
|
||||
{
|
||||
text += ".tgz";
|
||||
textBoxFileName.Text = text;
|
||||
}
|
||||
else if (radioButtonCompGz.Checked)
|
||||
{
|
||||
text += ".gz";
|
||||
textBoxFileName.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select the file for read/write and setup defaults for whether we're using compression based on extension
|
||||
/// </summary>
|
||||
private void ChooseFile()
|
||||
{
|
||||
var dr = saveFileDialog1.ShowDialog();
|
||||
if (dr != DialogResult.OK)
|
||||
return;
|
||||
|
||||
textBoxFileName.Text = saveFileDialog1.FileName;
|
||||
TextBoxFileNameTextChanged(this, null);
|
||||
}
|
||||
|
||||
private void TextBoxFileNameTextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (textBoxFileName.Text.ToLower().EndsWith(".tar.gz") || textBoxFileName.Text.ToLower().EndsWith(".tgz"))
|
||||
radioButtonCompTgz.Checked = true;
|
||||
else if (textBoxFileName.Text.ToLower().EndsWith(".gz"))
|
||||
radioButtonCompGz.Checked = true;
|
||||
else if (textBoxFileName.Text.ToLower().EndsWith(".zip"))
|
||||
radioButtonCompZip.Checked = true;
|
||||
else if (textBoxFileName.Text.ToLower().EndsWith(".img") || textBoxFileName.Text.ToLower().EndsWith(".bin") || textBoxFileName.Text.ToLower().EndsWith(".sdcard"))
|
||||
radioButtonCompNone.Checked = true;
|
||||
|
||||
if (radioButtonCompNone.Checked)
|
||||
_eCompType = EnumCompressionType.None;
|
||||
else if (radioButtonCompTgz.Checked)
|
||||
_eCompType = EnumCompressionType.Targzip;
|
||||
else if (radioButtonCompGz.Checked)
|
||||
_eCompType = EnumCompressionType.Gzip;
|
||||
else if (radioButtonCompZip.Checked)
|
||||
_eCompType = EnumCompressionType.Zip;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load in the drives
|
||||
/// </summary>
|
||||
private void PopulateDrives()
|
||||
{
|
||||
if (InvokeRequired)
|
||||
|
|
@ -222,6 +334,11 @@ namespace DynamicDevices.DiskWriter
|
|||
comboBoxDrives.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when removable media is inserted or removed, repopulates the drive list
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void WatcherEventArrived(object sender, EventArgs e)
|
||||
{
|
||||
if(InvokeRequired)
|
||||
|
|
@ -238,6 +355,10 @@ namespace DynamicDevices.DiskWriter
|
|||
DisableButtons(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates UI to disable buttons
|
||||
/// </summary>
|
||||
/// <param name="running">Whether read/write process is running</param>
|
||||
private void DisableButtons(bool running)
|
||||
{
|
||||
buttonRead.Enabled = false;
|
||||
|
|
@ -246,9 +367,13 @@ namespace DynamicDevices.DiskWriter
|
|||
buttonCancel.Enabled = running;
|
||||
comboBoxDrives.Enabled = false;
|
||||
textBoxFileName.Enabled = false;
|
||||
buttonChooseFile.Enabled = false;
|
||||
buttonChooseFile.Enabled = false;
|
||||
groupBoxCompression.Enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates UI to enable buttons
|
||||
/// </summary>
|
||||
private void EnableButtons()
|
||||
{
|
||||
buttonRead.Enabled = true;
|
||||
|
|
@ -258,6 +383,7 @@ namespace DynamicDevices.DiskWriter
|
|||
comboBoxDrives.Enabled = true;
|
||||
textBoxFileName.Enabled = true;
|
||||
buttonChooseFile.Enabled = true;
|
||||
groupBoxCompression.Enabled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -120,9 +120,6 @@
|
|||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>133, 17</value>
|
||||
</metadata>
|
||||
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>273, 17</value>
|
||||
</metadata>
|
||||
|
|
|
|||
|
|
@ -35,5 +35,5 @@ using System.Runtime.InteropServices;
|
|||
// 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.0.1.*")]
|
||||
[assembly: AssemblyFileVersion("1.0.1.0")]
|
||||
[assembly: AssemblyVersion("1.0.2.*")]
|
||||
[assembly: AssemblyFileVersion("1.0.2.0")]
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -5,16 +5,34 @@ A Windows Disk Imager. A C#.NET utility for reading / writing SD cards and USB d
|
|||
|
||||
Inspired by the excellent Win32DiskImager - http://sourceforge.net/projects/win32diskimager/
|
||||
|
||||
The current release can be downloaded here - http://www.dynamicdevices.co.uk/downloads/DiskImager-latest.exe
|
||||
|
||||
This utility is a C#.NET implementation, and adds a couple of features I wanted to see:
|
||||
|
||||
- reads/writes images to/from compressed file formats: ZIP, TGZ, GZ
|
||||
|
||||
- remembers the last file you read/write
|
||||
|
||||
- provides more file filters within file dialog for typical image files (.img, .bin, .sdcard)
|
||||
|
||||
- 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!**
|
||||
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
1.0.0 08/11/13 AJL Initial Commit. Reads and Writes SD cards
|
||||
1.0.2 09/11/13 AJL Added support for reading and writing directly to compressed formats: .zip, .tgz, .gz
|
||||
|
||||
Testing - Windows 8.1 Professional
|
||||
|
||||
1.0.1 08/11/13 AJL Refactoring for cleanup. Fixed issue with SEH exception due to SafeHandle disposal
|
||||
|
||||
Testing - Windows 8.1 Professional
|
||||
Testing - Windows 8.1 Professional
|
||||
|
||||
1.0.0 08/11/13 AJL Initial Commit. Reads and Writes SD cards
|
||||
|
||||
Testing - Windows 8.1 Professional
|
||||
|
||||
Contact
|
||||
=======
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue