private void txtFileName_TextChanged(object sender, EventArgs e) { var fn = txtFileName.Text; ParsedChangeFile.PARTITION_RECORD[] pt = null; try { if (File.Exists(fn)) { pt = ParsedChangeFile.ReadPartitionTable(fn); } } catch { } if (pt != null && pt.Length > 0 && pt[pt.Length - 1].Type == 0x83) { cbResize.Checked = cbResize.Enabled = true; cbResize.Text = string.Format(cbResize.Tag.ToString(), " (" + StringHelpers.FormatByteCount(pt[pt.Length - 1].TotalSectorCount * 512L) + ")"); } else { cbResize.Checked = cbResize.Enabled = false; cbResize.Text = string.Format(cbResize.Tag.ToString(), ""); } }
bool AttemptWrite(ThreadContext ctx, DiskDevice dev) { long totalSize = ctx.fs.Length, done = 0; const int bufferSize = 1024 * 1024; IntPtr buffer = IntPtr.Zero; var start = DateTime.Now; try { dev.SeekAbs(0); byte[] firstSector = null; //The very first sector will be written in the very end. Otherwise the partition driver might block us from writing the raw disk object. buffer = Marshal.AllocCoTaskMem(bufferSize); while (done < totalSize) { if (_AbortWriting) { throw new OperationCanceledException(); } int todo = (int)Math.Min(bufferSize, totalSize - done), cdone; if (!DeviceControl.ReadFile(ctx.fs.SafeFileHandle, buffer, todo, out cdone, IntPtr.Zero) || cdone != todo) { if (!AskRetry("Cannot read image file at offset " + done.ToString())) { throw new OperationCanceledException(); } else { return(false); } } if (firstSector == null) { firstSector = new byte[SectorSize]; Marshal.Copy(buffer, firstSector, 0, SectorSize); Marshal.Copy(new byte[SectorSize], 0, buffer, SectorSize); } if ((todo % SectorSize) != 0) { //If the image file is not aligned to the sector boundary, the device write would fail unless we manually align it todo = ((todo + SectorSize - 1) / SectorSize) * SectorSize; } if (dev.Write(buffer, todo) != todo) { if (!AskRetry("Cannot write medium at offset " + done.ToString())) { throw new OperationCanceledException(); } else { return(false); } } dev.SeekRel(todo); string statusText; long msec = (long)(DateTime.Now - start).TotalMilliseconds; if (msec < 5000) { statusText = string.Format("Writing ({0}B done)...", StringHelpers.FormatByteCount(done)); } else { long bps = (done * 1000) / msec; long bytesLeft = totalSize - done; if (bps == 0) { bps = 1; } int secEstimated = (int)(bytesLeft / bps); statusText = string.Format("Writing ({0}B done, {1}B/s, {2}:{3:d2} remaining)...", StringHelpers.FormatByteCount(done), StringHelpers.FormatByteCount(bps), secEstimated / 60, secEstimated % 60); } UpdateProgress(statusText, done, totalSize); done += todo; } if (firstSector == null) { throw new Exception("First sector not cached"); } if (ctx.ResizedPartition.HasValue) { string resizeDir = Path.Combine(Path.GetTempPath(), "resize2fs." + Process.GetCurrentProcess().Id); Directory.CreateDirectory(resizeDir); string resizer = Path.Combine(resizeDir, "resize2fs.exe"); using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream("WinFlashTool.resize2fs.exe")) { byte[] data = new byte[s.Length]; s.Read(data, 0, data.Length); File.WriteAllBytes(resizer, data); } var devLength = dev.QueryLength().Length; if ((ctx.ResizedPartition.Value.StartingLBA + ctx.ResizedPartition.Value.TotalSectorCount) * 512UL > devLength) { throw new ResizeSkippedException("Image is too small"); } var pt = ParsedChangeFile.ReadPartitionTable(firstSector); int partitionNumber = -1; for (int i = 0; i < pt.Length; i++) { if (pt[i].Equals(ctx.ResizedPartition.Value)) { partitionNumber = i; break; } } if (partitionNumber == -1) { throw new ResizeSkippedException("Matching partition not found in image"); } ulong newSizeInBytes = devLength - ctx.ResizedPartition.Value.StartingLBA * 512UL; int offsetInBootSector = 0x1BE + partitionNumber * 0x10 + 0x0c; if (BitConverter.ToUInt32(firstSector, offsetInBootSector) != ctx.ResizedPartition.Value.TotalSectorCount) { throw new ResizeSkippedException("Internal error: wrong partition table offset"); } BitConverter.GetBytes((int)(newSizeInBytes / 512)).CopyTo(firstSector, offsetInBootSector); UpdateProgress("Resizing file system...", 0, 0); var info = new ProcessStartInfo { FileName = resizer, Arguments = string.Format("-f \"{0}@{1}/{2}\"", ctx.FileName, ctx.ResizedPartition.Value.StartingLBA * 512L, newSizeInBytes), CreateNoWindow = true, UseShellExecute = false, }; info.EnvironmentVariables["RESIZE2FS_CHANGE_FILE_DIR"] = resizeDir; string chg = Path.Combine(resizeDir, Path.GetFileName(ctx.FileName) + ".chg"); var proc = Process.Start(info); proc.WaitForExit(); if (proc.ExitCode != 0) { throw new ResizeSkippedException("Failed to resize Ext2FS - exit code " + proc.ExitCode); } if (!File.Exists(chg)) { throw new ResizeSkippedException("Resize change file does not exist: " + chg); } UpdateProgress("Writing resized file system...", 0, 0); using (var chf = new ParsedChangeFile(chg, ctx.ResizedPartition.Value.StartingLBA * 512, devLength)) { chf.Apply(dev, (d, t) => UpdateProgress("Writing resized file system...", d, t)); } try { Directory.Delete(resizeDir, true); } catch { } } dev.SeekAbs(0); dev.Write(firstSector); } finally { if (buffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(buffer); } } return(true); }
private void button3_Click(object sender, EventArgs e) { DiskDevice dev = null; FileStream fs = null; try { if (!File.Exists(txtFileName.Text)) { throw new Exception("Please select a valid image file"); } if (lvDevices.SelectedItems.Count == 0) { throw new Exception("Please select target device"); } var rec = lvDevices.SelectedItems[0].Tag as DiskRecord; var info = rec?.Info; if (info == null) { throw new Exception("Please select a valid target device"); } string devPath = info.DevicePath; dev = new DiskDevice(devPath); long volumeSize = 0; byte[] result = new byte[8]; if (dev.DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO, null, result) == 8) { volumeSize = BitConverter.ToInt64(result, 0); } if (volumeSize <= 0) { throw new Exception("Please insert a card into the card reader"); } fs = File.Open(txtFileName.Text, FileMode.Open, FileAccess.Read, FileShare.Read); if (fs.Length > volumeSize) { throw new Exception(string.Format("The selected media ({0}) is too small for the selected image file {1})", StringHelpers.FormatByteCount(volumeSize), StringHelpers.FormatByteCount(fs.Length))); } _RegHelper.SetValue("LastImageFile", txtFileName.Text); var number = dev.QueryDeviceNumber(); if (new EraseConfirmationForm(info, dev, volumeSize).ShowDialog() != DialogResult.OK) { return; } lblProgress.Text = "Preparing..."; GUIEnabled = false; _AbortWriting = false; var ctx = new ThreadContext { VolumeSize = volumeSize, DeviceNumber = number, fs = fs, devID = info.DeviceID, FileName = txtFileName.Text }; if (cbResize.Checked) { try { var pt = ParsedChangeFile.ReadPartitionTable(ctx.FileName); if (pt != null && pt.Length > 0 && pt[pt.Length - 1].Type == 0x83) { ctx.ResizedPartition = pt[pt.Length - 1]; } } catch { } } new Thread(WriteThreadBody).Start(ctx); fs = null; dev = null; } catch (System.Exception ex) { MessageBox.Show(ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { fs?.Dispose(); dev?.Dispose(); } }