/// <summary> /// Sets the size of disk the device. /// </summary> /// <param name="device">The device to query</param> /// <param name="token">The cancellation token.</param> protected void SetDeviceSize(SystemDevice device, CancellationToken token) { DISK_GEOMETRY_EX diskGeometry; if (DeviceIoControl<int>.IsAccessible(device) == false) { // Device is not ready return; } token.ThrowIfCancellationRequested(); diskGeometry = base.GetDriveGeometry(device); token.ThrowIfCancellationRequested(); device.DiskSize = diskGeometry.DiskSize; device.BytesPerSector = diskGeometry.Geometry.BytesPerSector; device.SectorsCount = diskGeometry.Geometry.SectorsCount; }
/// <summary> /// Extracts the disk to provided file /// </summary> /// <param name="device">The device to extract from</param> /// <param name="outputFileName">Name of the output file including path</param> /// <param name="progressCallback">The progress callback.</param> /// <param name="token">The cancellation token.</param> /// <returns>Task that execute the process and return total number of bytes read from device</returns> internal Task<long> ExtractDisk(SystemDevice device, string outputFileName, IProgress<double> progressCallback, CancellationToken token) { return engine.ExtractDiskAsync(device, outputFileName, progressCallback, token); }
/// <summary> /// Function will query device for unique device number and set it on <see cref="SystemDevice"/> object /// </summary> /// <param name="device">The device.</param> /// <param name="token">The token.</param> protected void SetDeviceNumber(SystemDevice device, CancellationToken token) { STORAGE_DEVICE_NUMBER devNumber; if (DeviceIoControl<int>.IsAccessible(device) == false) { // Device is not ready return; } token.ThrowIfCancellationRequested(); devNumber = base.GetDeviceNumber(device); token.ThrowIfCancellationRequested(); device.DeviceNumber = devNumber.DeviceNumber; }
public Task<long> ExtractDiskAsync(SystemDevice device, string outputFile, IProgress<double> progress, CancellationToken token) { if (deviceBuilder.IfUserAdmin() == false) { throw new System.Security.SecurityException("User must be administrator to access the hardware. Please re-login"); } // // If bufferSize will be tooo small (like: 512 bytes) the iteration of ReadFile will fail with E_FAIL or some SEH exception :( int sectorsReadAtOnce = Convert.ToInt32(device.SectorsCount / 100) + 1; // in 'sectors' not bytes ! int bufferSize = sectorsReadAtOnce * device.BytesPerSector; // // Align to 512 exactly //while (bufferSize % device.BytesPerSector != 0) // bufferSize--; byte[] buffer = new byte[bufferSize]; long bytesRead = 0; uint lpNumberOfBytesRead = 0; bool functionResult = false; int win32err = 0; NativeOverlapped nativeOverlapped = new NativeOverlapped(); SystemDevice device2 = new SystemDevice("\\\\.\\PhysicalDrive" + device.DeviceNumber); GCHandle gcHandle = new GCHandle(); return Task.Factory.StartNew<long>(() => { try { IntPtr deviceHandle = device2.OpenDeviceHandle(); gcHandle = GCHandle.Alloc(deviceHandle); // So it won't be collected by GC while I'm doing PInvoke BinaryWriter writer = GetOutputStream(outputFile); while(true) { functionResult = UnsafeNativeMethods.ReadFile(deviceHandle, buffer, Convert.ToUInt32(buffer.Length), ref lpNumberOfBytesRead, ref nativeOverlapped); win32err = Marshal.GetLastWin32Error(); if (functionResult) { bytesRead += lpNumberOfBytesRead; writer.Write(buffer, 0, buffer.Length); } else { if (win32err == UnsafeNativeMethods.ERROR_SECTOR_NOT_FOUND) { // This is a device black-hole // try to squeeze as much as I can if (bufferSize == device.BytesPerSector) { // That's the last one break; } else { bufferSize = device.BytesPerSector; buffer = new byte[bufferSize]; } } else { throw new System.ComponentModel.Win32Exception(win32err); } } if (progress != null) { progress.Report(Math.Round((double)((bytesRead * 100) / device.DiskSize.Value))); } // Must not (!) increase position - everything will be read to NULL //deviceStream.Position = iCounter; if (bytesRead + bufferSize > device.DiskSize.Value) { if (device.DiskSize.Value == bytesRead) { // all done break; } else { // Collect leftovers buffer = new byte[(bytesRead + bufferSize) - device.DiskSize.Value]; } } GC.KeepAlive(deviceHandle); } writer.Flush(); gcHandle.Free(); device.CloseDeviceHandle(); return bytesRead; } catch (SEHException seh) { gcHandle.Free(); System.Diagnostics.Trace.WriteLine("[]--- SEHException in ExtractDiskAsync(): " + seh.ToString()); return 0; } catch (Exception exp_gen) { gcHandle.Free(); if (win32err == 0) { win32err = Marshal.GetLastWin32Error(); } var zz = new System.ComponentModel.Win32Exception(win32err); System.Diagnostics.Trace.WriteLine("[]--- Exception in ExtractDiskAsync(): " + exp_gen.ToString()); System.Diagnostics.Trace.WriteLine("[]--- Exception in ExtractDiskAsync() (native) : " + zz.ToString()); return 0; } } , token); }