/// <summary> /// /// </summary> /// <param name="driveLetter"></param> /// <param name="fileName"></param> /// <param name="eCompType"></param> /// <returns></returns> public bool WriteDrive(string driveLetter, string fileName, EnumCompressionType eCompType) { IsCancelling = false; var dtStart = DateTime.Now; if (!File.Exists(fileName)) { throw new ArgumentException(fileName + " doesn't exist"); } // // 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 buffer = new byte[Globals.MaxBufferSize]; long offset = 0; var fileLength = new FileInfo(fileName).Length; var uncompressedlength = fileLength; var errored = true; using (var basefs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { Stream fs; switch (eCompType) { case EnumCompressionType.Zip: { var zipFile = new ZipFile(basefs); var ze = (from ZipEntry zipEntry in zipFile where zipEntry.IsFile select zipEntry).FirstOrDefault(); if (ze == null) { LogMsg(@"Error reading zip input stream"); goto readfail2; } var zis = zipFile.GetInputStream(ze); uncompressedlength = ze.Size; fs = zis; } break; case EnumCompressionType.Gzip: { var gzis = new GZipInputStream(basefs) { IsStreamOwner = true }; uncompressedlength = gzis.Length; fs = gzis; } break; case EnumCompressionType.Targzip: { var gzos = new GZipInputStream(basefs) { IsStreamOwner = true }; var tis = new TarInputStream(gzos); TarEntry tarEntry; do { tarEntry = tis.GetNextEntry(); } while (tarEntry.IsDirectory); uncompressedlength = tarEntry.Size; fs = tis; } break; default: // No compression - direct to file stream fs = basefs; uncompressedlength = fs.Length; break; } var bufferOffset = 0; using (var br = new BinaryReader(fs)) { while (offset < uncompressedlength && !IsCancelling) { // 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; 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; // 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 (_diskAccess.Write(buffer, bytesToWrite, out wroteBytes) < 0) { LogMsg(@"Error writing data to drive: " + Marshal.GetHRForLastWin32Error()); goto readfail1; } if (wroteBytes != bytesToWrite) { LogMsg(@"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 / uncompressedlength); var tsElapsed = DateTime.Now.Subtract(dtStart); var bytesPerSec = offset / tsElapsed.TotalSeconds; Progress(percentDone); LogMsg(@"Wrote " + percentDone + @"%, " + (offset / (1024 * 1024)) + @" MB / " + (uncompressedlength / (1024 * 1024) + " MB, " + string.Format("{0:F}", (bytesPerSec / (1024 * 1024))) + @" MB/sec, Elapsed time: " + tsElapsed.ToString(@"dd\.hh\:mm\:ss"))); } } } errored = false; readfail1: _diskAccess.Close(); readfail2: _diskAccess.UnlockDrive(); var tstotalTime = DateTime.Now.Subtract(dtStart); if (IsCancelling) { LogMsg("Cancelled"); } else { LogMsg("All Done - Wrote " + offset + " bytes. Elapsed time " + tstotalTime.ToString(@"dd\.hh\:mm\:ss")); } Progress(0); return(!errored); }
/// <summary> /// /// </summary> /// <param name="driveLetter"></param> /// <param name="fileName"></param> /// <param name="eCompType"></param> /// <param name="removeAfter"></param> /// <returns></returns> public bool WriteDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool removeAfter) { IsCancelling = false; var dtStart = DateTime.Now; if (!File.Exists(fileName)) { throw new ArgumentException(fileName + Resources.Disk_WriteDrive__doesn_t_exist); } // // Get physical drive partition for logical partition // var physicalDrive = _diskAccess.GetPhysicalPathForLogicalPath(driveLetter); if (string.IsNullOrEmpty(physicalDrive)) { LogMsg(Resources.Disk_WriteDrive_Error__Couldn_t_map_partition_to_physical_drive); _diskAccess.UnlockDrive(); return(false); } // // Lock logical drive // var success = _diskAccess.LockDrive(driveLetter); if (!success) { LogMsg(Resources.Disk_WriteDrive_Failed_to_lock_drive); return(false); } // // Get drive size // var driveSize = _diskAccess.GetDriveSize(physicalDrive); if (driveSize <= 0) { LogMsg(Resources.Disk_WriteDrive_Failed_to_get_device_size); _diskAccess.UnlockDrive(); return(false); } // // Open the physical drive // var physicalHandle = _diskAccess.Open(physicalDrive); if (physicalHandle == null) { LogMsg(Resources.Disk_WriteDrive_Failed_to_open_physical_drive); _diskAccess.UnlockDrive(); return(false); } var buffer = new byte[Globals.MaxBufferSize]; long offset = 0; var fileLength = new FileInfo(fileName).Length; var uncompressedlength = fileLength; var errored = true; using (var basefs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { Stream fs; switch (eCompType) { case EnumCompressionType.Zip: var zipFile = new ZipFile(basefs); var ze = (from ZipEntry zipEntry in zipFile where zipEntry.IsFile select zipEntry).FirstOrDefault(); if (ze == null) { LogMsg(Resources.Disk_WriteDrive_Error_reading_zip_input_stream); goto readfail2; } var zis = zipFile.GetInputStream(ze); uncompressedlength = ze.Size; fs = zis; break; case EnumCompressionType.Gzip: var gzis = new GZipInputStream(basefs) { IsStreamOwner = true }; uncompressedlength = gzis.Length; fs = gzis; break; case EnumCompressionType.Targzip: var gzos = new GZipInputStream(basefs) { IsStreamOwner = true }; var tis = new TarInputStream(gzos); TarEntry tarEntry; do { tarEntry = tis.GetNextEntry(); } while (tarEntry.IsDirectory); uncompressedlength = tarEntry.Size; fs = tis; break; case EnumCompressionType.XZ: var xzs = new XZInputStream(basefs); uncompressedlength = xzs.Length; fs = xzs; break; default: // No compression - direct to file stream fs = basefs; uncompressedlength = fs.Length; break; } var bufferOffset = 0; using (var br = new BinaryReader(fs)) { while (offset < uncompressedlength && !IsCancelling) { // 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; 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; // 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 (_diskAccess.Write(buffer, bytesToWrite, out wroteBytes) < 0) { LogMsg(Resources.Disk_WriteDrive_Error_writing_data_to_drive__ + Marshal.GetHRForLastWin32Error()); goto readfail1; } if (wroteBytes != bytesToWrite) { LogMsg(Resources.Disk_WriteDrive_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 / uncompressedlength); var tsElapsed = DateTime.Now.Subtract(dtStart); var bytesPerSec = offset / tsElapsed.TotalSeconds; Progress(percentDone); LogMsg(Resources.Disk_WriteDrive_Wrote + @": " + (offset / Globals.MbModifier) + @" / " + (uncompressedlength / Globals.MbModifier) + " MB; " + string.Format("{0:F}", (bytesPerSec / Globals.MbModifier)) + @" MB/s; " + Resources.Disk_Elapsed_time + ": " + tsElapsed.ToString(@"hh\:mm\:ss")); } } if (fs is ZipOutputStream) { ((ZipOutputStream)fs).CloseEntry(); ((ZipOutputStream)fs).Close(); } else if (fs is TarOutputStream) { ((TarOutputStream)fs).CloseEntry(); fs.Close(); } else if (fs is GZipOutputStream) { fs.Close(); } else if (fs is XZOutputStream) { fs.Close(); } } errored = false; if (removeAfter && !IsCancelling) { _diskAccess.UnmountDrive(); } readfail1: _diskAccess.Close(); readfail2: _diskAccess.UnlockDrive(); var tstotalTime = DateTime.Now.Subtract(dtStart); if (IsCancelling) { LogMsg(Resources.Disk_WriteDrive_Cancelled); } else { LogMsg(Resources.Disk_WriteDrive_Wrote + @" " + offset + @" " + Resources.Disk_WriteDrive_bytes + @". " + Resources.Disk_Elapsed_time + @": " + tstotalTime.ToString(@"hh\:mm\:ss")); } Progress(0); return(!errored); }