Ejemplo n.º 1
0
        public static Dictionary <int, string> GetVolumesForPhysicalDisk(int deviceNumber)
        {
            StringBuilder volName = new StringBuilder(260);
            IntPtr        hVolume = FindFirstVolume(volName, volName.Capacity);
            var           result  = new Dictionary <int, string>();

            if (hVolume == (IntPtr)(-1))
            {
                return(result);
            }
            do
            {
                try
                {
                    using (var dev = new DiskDevice(volName.ToString().TrimEnd('\\'), true))
                    {
                        var dn = dev.QueryDeviceNumber();
                        if (dn == null || dn.DeviceNumber != deviceNumber)
                        {
                            continue;
                        }
                        result[dn.PartitionNumber] = volName.ToString();
                    }
                }
                catch
                {
                }
            } while (FindNextVolume(hVolume, volName, volName.Capacity));

            FindVolumeClose(hVolume);
            return(result);
        }
Ejemplo n.º 2
0
        List <DiskRecord> QueryAllDisks()
        {
            List <DiskRecord> disks = new List <DiskRecord>();

            try
            {
                using (var devenum = new DeviceEnumerator(GUID_DEVINTERFACE_DISK))
                    foreach (var info in devenum.GetAllDevices())
                    {
                        long volumeSize = 0;
                        DiskDevice.STORAGE_HOTPLUG_INFO      hotplug = null;
                        DiskDevice.STORAGE_DEVICE_DESCRIPTOR desc    = null;
                        try
                        {
                            using (var dev = new DiskDevice(info.DevicePath))
                            {
                                try
                                {
                                    hotplug = dev.QueryHotplugInfo();
                                }
                                catch (Exception ex)
                                {
                                }

                                try
                                {
                                    desc = dev.QueryDeviceDescriptor();
                                }
                                catch
                                {
                                }

                                byte[] result = new byte[8];
                                try
                                {
                                    if (dev.DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO, null, result) == 8)
                                    {
                                        volumeSize = BitConverter.ToInt64(result, 0);
                                    }
                                }
                                catch
                                {
                                }
                            }

                            disks.Add(new DiskRecord {
                                Descriptor = desc, Hotplug = hotplug, Info = info, VolumeSize = volumeSize
                            });
                        }
                        catch { }
                    }
            }
            catch
            {
            }
            return(disks);
        }
Ejemplo n.º 3
0
        public void Apply(DiskDevice dev, ProgressDelegate progress)
        {
            byte[] tmp = null;
            long   total = 0, done = 0;

            foreach (var chg in _WriteOps)
            {
                total += chg.SizeInBytes;
            }

            foreach (var chg in _WriteOps)
            {
                if (tmp == null || tmp.Length < chg.SizeInBytes)
                {
                    tmp = new byte[chg.SizeInBytes];
                }

                if (chg.Zero)
                {
                    for (int i = 0; i < chg.SizeInBytes; i++)
                    {
                        tmp[i] = 0;
                    }
                }
                else
                {
                    _File.Seek((long)chg.OffsetInFile, SeekOrigin.Begin);
                    if (_File.Read(tmp, 0, chg.SizeInBytes) != chg.SizeInBytes)
                    {
                        throw new Exception("Failed to read change file at offset " + chg.OffsetInFile);
                    }
                }

                dev.SeekAbs((long)chg.OffsetInDevice);
                if (dev.Write(tmp, chg.SizeInBytes) != chg.SizeInBytes)
                {
                    throw new Exception("Failed to write change at offset " + chg.OffsetInDevice);
                }

                done += chg.SizeInBytes;
                if (progress != null)
                {
                    progress(done, total);
                }
            }
        }
Ejemplo n.º 4
0
        void WriteThreadBody(object obj)
        {
            ThreadContext ctx = (ThreadContext)obj;

            try
            {
                UpdateProgress("Erasing partition table...", 0, 0);

                using (var dev = new DiskDevice(ctx.DeviceNumber.PhysicalDrive))
                {
                    if (dev.QueryLength().Length != (ulong)ctx.VolumeSize)
                    {
                        throw new Exception("Mismatching volume length");
                    }
                }

                RunDiskpart($"SELECT DISK {ctx.DeviceNumber.DeviceNumber}\r\nCLEAN\r\nRESCAN\r\nEXIT", $"Diskpart failed to reset disk #{ctx.DeviceNumber}");

                using (var dev = new DiskDevice(ctx.DeviceNumber.PhysicalDrive))
                {
                    for (; ;)
                    {
                        if (AttemptWrite(ctx, dev))
                        {
                            break;
                        }
                    }

                    ReportCompletion(null);
                }
            }
            catch (System.Exception ex)
            {
                ReportCompletion(ex);
            }
            finally
            {
                ctx.fs?.Dispose();
            }
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        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();
            }
        }
Ejemplo n.º 7
0
        public EraseConfirmationForm(DeviceEnumerator.DeviceInfo info, DiskDevice dev, long volumeSize)
        {
            InitializeComponent();
            this.info = info;

            lblDevName.Text = info.UserFriendlyName;
            lblDevSize.Text = StringHelpers.FormatByteCount(volumeSize) + "B";

            var num = dev.QueryDeviceNumber();

            if (num == null)
            {
                lblInternalName.Text = "Unknown";
            }
            else
            {
                lblInternalName.Text = num.PhysicalDrive;
            }

            Dictionary <int, string> volumesByPartitionNumbers = null;

            try
            {
                if (num != null)
                {
                    volumesByPartitionNumbers = VolumeManager.GetVolumesForPhysicalDisk(num.DeviceNumber);
                }
            }
            catch
            {
            }

            var layout = dev.QueryLayoutInformation();

            if (layout != null)
            {
                for (int i = 0; i < layout.PartitionCount; i++)
                {
                    if (layout.PartitionEntry[i].PartitionType == 0)
                    {
                        continue;
                    }

                    ListViewItem lvi = new ListViewItem((i + 1).ToString());
                    lvi.SubItems.Add(StringHelpers.FormatByteCount(layout.PartitionEntry[i].StartingOffset) + "B");
                    lvi.SubItems.Add(StringHelpers.FormatByteCount(layout.PartitionEntry[i].PartitionLength) + "B");
                    lvi.SubItems.Add(MapPartitionType(layout.PartitionEntry[i].PartitionType));

                    string volID;
                    bool   found = false;
                    if (volumesByPartitionNumbers != null && volumesByPartitionNumbers.TryGetValue(layout.PartitionEntry[i].PartitionNumber, out volID))
                    {
                        volumesByPartitionNumbers.Remove(layout.PartitionEntry[i].PartitionNumber);
                        string mountPoints = VolumeManager.GetVolumeMountPoints(volID, '|');
                        if (mountPoints != null)
                        {
                            lvi.Tag = mountPoints.Split('|')[0];
                            lvi.SubItems.Add(mountPoints.Replace("|", ";  "));
                            found = mountPoints.Length > 0;
                        }
                    }

                    lvi.ImageIndex = found ? 0 : 1;

                    lvPartitions.Items.Add(lvi);
                }
            }
        }