/// <summary> /// Read data direct from drive to file /// </summary> /// <param name="driveLetter"></param> /// <param name="fileName"></param> /// <param name="eCompType"></param> /// <returns></returns> public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR, long start, long length) { IsCancelling = false; var dtStart = DateTime.Now; // // Map to physical drive // 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); } var readSize = driveSize; // // Open the physical drive // var physicalHandle = _diskAccess.Open(physicalDrive); if (physicalHandle == null) { LogMsg(@"Failed to open physical drive"); _diskAccess.UnlockDrive(); return(false); } // // Start doing the read // var buffer = new byte[Globals.MaxBufferSize]; var offset = 0L; 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); fs = tos; } break; default: // No compression - direct to file stream fs = basefs; break; } while (offset < readSize && !IsCancelling) { // NOTE: If we provide a buffer that extends past the end of the physical device ReadFile() doesn't // 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)readSize - (ulong)offset) < (ulong)buffer.Length) ? ((ulong)readSize - (ulong)offset) : (ulong)buffer.Length); int readBytes; if (_diskAccess.Read(buffer, readMaxLength, out readBytes) < 0) { LogMsg(@"Error reading data from drive: " + Marshal.GetHRForLastWin32Error()); goto readfail1; } if (readBytes == 0) { LogMsg(@"Error reading data from drive - past EOF?"); goto readfail1; } // Check MBR if (bUseMBR && offset == 0) { var truncatedSize = ParseMBRForSize(buffer); if (truncatedSize > driveSize) { LogMsg("Problem with filesystem. It reports it is larger than the disk!"); goto readfail1; } if (truncatedSize == 0) { LogMsg("No valid partitions on drive"); goto readfail1; } readSize = truncatedSize; } if (offset == 0) { switch (eCompType) { case EnumCompressionType.Targzip: 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 = readSize; tarEntry.ModTime = DateTime.SpecifyKind(fi.LastWriteTime, DateTimeKind.Utc); ((TarOutputStream)fs).PutNextEntry(tarEntry); break; } } fs.Write(buffer, 0, readBytes); offset += (uint)readBytes; var percentDone = (int)(100 * offset / readSize); var tsElapsed = DateTime.Now.Subtract(dtStart); var bytesPerSec = offset / tsElapsed.TotalSeconds; Progress(percentDone); LogMsg(@"Read " + percentDone + @"%, " + (offset / (1024 * 1024)) + @" MB / " + (readSize / (1024 * 1024) + " MB (Physical: " + (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(); ((ZipOutputStream)fs).Close(); } if (fs is TarOutputStream) { ((TarOutputStream)fs).CloseEntry(); ((TarOutputStream)fs).Close(); } if (fs is GZipOutputStream) { // ((GZipOutputStream) fs).Finish(); ((GZipOutputStream)fs).Close(); } } readfail1: _diskAccess.Close(); _diskAccess.UnlockDrive(); var tstotalTime = DateTime.Now.Subtract(dtStart); if (IsCancelling) { LogMsg("Cancelled"); } else { LogMsg("All Done - Read " + offset + " bytes. Elapsed time " + tstotalTime.ToString(@"dd\.hh\:mm\:ss")); } Progress(0); return(true); }
/// <summary> /// Read data direct from drive to file /// </summary> /// <param name="driveLetter"></param> /// <param name="fileName"></param> /// <param name="eCompType"></param> /// <returns></returns> public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR) { IsCancelling = false; var dtStart = DateTime.Now; // // Map to physical drive // 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); } var readSize = driveSize; // // 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); } // // Start doing the read // var buffer = new byte[Globals.MaxBufferSize]; var offset = 0L; 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 gzis = new GZipOutputStream(basefs); gzis.SetLevel(Globals.CompressionLevel); gzis.IsStreamOwner = true; fs = gzis; break; case EnumCompressionType.Targzip: var gzos = new GZipOutputStream(basefs); gzos.SetLevel(Globals.CompressionLevel); gzos.IsStreamOwner = true; var tos = new TarOutputStream(gzos); fs = tos; break; case EnumCompressionType.XZ: var xzs = new XZOutputStream(basefs); fs = xzs; break; default: // No compression - direct to file stream fs = basefs; break; } while (offset < readSize && !IsCancelling) { // NOTE: If we provide a buffer that extends past the end of the physical device ReadFile() doesn't // 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)readSize - (ulong)offset) < (ulong)buffer.Length) ? ((ulong)readSize - (ulong)offset) : (ulong)buffer.Length); int readBytes; if (_diskAccess.Read(buffer, readMaxLength, out readBytes) < 0) { LogMsg(Resources.Disk_ReadDrive_Error_reading_data_from_drive__ + Marshal.GetHRForLastWin32Error()); goto readfail1; } if (readBytes == 0) { LogMsg(Resources.Disk_ReadDrive_Error_reading_data_from_drive___past_EOF_); goto readfail1; } // Check MBR if (bUseMBR && offset == 0) { var truncatedSize = ParseMBRForSize(buffer); if (truncatedSize > driveSize) { LogMsg(Resources.Disk_ReadDrive_Problem_with_filesystem__It_reports_it_is_larger_than_the_disk_); goto readfail1; } if (truncatedSize == 0) { LogMsg(Resources.Disk_ReadDrive_No_valid_partitions_on_drive); goto readfail1; } readSize = truncatedSize; } if (offset == 0) { switch (eCompType) { case EnumCompressionType.Targzip: 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 = readSize; tarEntry.ModTime = DateTime.SpecifyKind(fi.LastWriteTime, DateTimeKind.Utc); ((TarOutputStream)fs).PutNextEntry(tarEntry); break; } } fs.Write(buffer, 0, readBytes); offset += (uint)readBytes; var percentDone = (int)(100 * offset / readSize); var tsElapsed = DateTime.Now.Subtract(dtStart); var bytesPerSec = offset / tsElapsed.TotalSeconds; Progress(percentDone); LogMsg(Resources.Disk_ReadDrive_Read + @": " + (offset / Globals.MbModifier) + @" / " + (readSize / Globals.MbModifier) + @" MB " + @"(" + Resources.Disk_ReadDrive_Physical + @": " + (driveSize / 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(); } } readfail1: _diskAccess.Close(); _diskAccess.UnlockDrive(); var tstotalTime = DateTime.Now.Subtract(dtStart); if (IsCancelling) { LogMsg(Resources.Disk_WriteDrive_Cancelled); } else { LogMsg(Resources.Disk_ReadDrive_All_Done_Read + @" " + offset + @" " + Resources.Disk_WriteDrive_bytes + @". " + Resources.Disk_Elapsed_time + @": " + tstotalTime.ToString(@"hh\:mm\:ss")); } Progress(0); return(true); }