2018-10-17 22:12:51 +01:00
|
|
|
// /***************************************************************************
|
|
|
|
|
// The Disc Image Chef
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : frmImageVerify.xeto.cs
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
//
|
2018-12-29 15:26:00 +00:00
|
|
|
// Component : Image verification window.
|
2018-10-17 22:12:51 +01:00
|
|
|
//
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Implements verifying media image.
|
|
|
|
|
//
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General public License as
|
|
|
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General public License
|
|
|
|
|
// along with this program. If not, see ;http://www.gnu.org/licenses/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
|
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using DiscImageChef.CommonTypes.Interfaces;
|
|
|
|
|
using DiscImageChef.CommonTypes.Structs;
|
|
|
|
|
using DiscImageChef.Console;
|
|
|
|
|
using DiscImageChef.Core;
|
|
|
|
|
using Eto.Forms;
|
|
|
|
|
using Eto.Serialization.Xaml;
|
|
|
|
|
|
|
|
|
|
namespace DiscImageChef.Gui.Forms
|
|
|
|
|
{
|
|
|
|
|
public class frmImageVerify : Form
|
|
|
|
|
{
|
|
|
|
|
bool cancel;
|
|
|
|
|
IMediaImage inputFormat;
|
|
|
|
|
|
|
|
|
|
public frmImageVerify(IMediaImage inputFormat)
|
|
|
|
|
{
|
|
|
|
|
this.inputFormat = inputFormat;
|
|
|
|
|
XamlReader.Load(this);
|
|
|
|
|
cancel = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void OnBtnStart(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
chkVerifyImage.Enabled = false;
|
|
|
|
|
chkVerifySectors.Enabled = false;
|
|
|
|
|
btnClose.Visible = false;
|
|
|
|
|
btnStart.Visible = false;
|
|
|
|
|
btnStop.Visible = true;
|
|
|
|
|
stkProgress.Visible = true;
|
|
|
|
|
lblProgress2.Visible = false;
|
|
|
|
|
|
|
|
|
|
new Thread(DoWork).Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DoWork()
|
|
|
|
|
{
|
|
|
|
|
bool? correctDisc = null;
|
|
|
|
|
long totalSectors = 0;
|
|
|
|
|
long errorSectors = 0;
|
|
|
|
|
long correctSectors = 0;
|
|
|
|
|
long unknownSectors = 0;
|
|
|
|
|
bool formatHasTracks;
|
|
|
|
|
|
|
|
|
|
try { formatHasTracks = inputFormat.Tracks?.Count > 0; }
|
|
|
|
|
catch { formatHasTracks = false; }
|
|
|
|
|
|
|
|
|
|
// Setup progress bars
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
stkProgress.Visible = true;
|
|
|
|
|
prgProgress.MaxValue = 0;
|
|
|
|
|
|
|
|
|
|
if(chkVerifyImage.Checked == true || chkVerifySectors.Checked == true) prgProgress.MaxValue = 1;
|
|
|
|
|
|
|
|
|
|
if(formatHasTracks) prgProgress.MaxValue += inputFormat.Tracks.Count;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(chkVerifySectors.Checked == true)
|
|
|
|
|
{
|
|
|
|
|
prgProgress.MaxValue = 2;
|
|
|
|
|
prgProgress2.Visible = false;
|
|
|
|
|
lblProgress2.Visible = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
prgProgress2.Visible = true;
|
|
|
|
|
lblProgress2.Visible = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prgProgress.MaxValue++;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if(chkVerifyImage.Checked == true)
|
|
|
|
|
{
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
lblProgress.Text = "Checking media image...";
|
|
|
|
|
if(chkVerifySectors.Checked == true) prgProgress.Value = 1;
|
|
|
|
|
else prgProgress.Indeterminate = true;
|
|
|
|
|
|
|
|
|
|
prgProgress2.Indeterminate = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
DateTime startCheck = DateTime.UtcNow;
|
|
|
|
|
bool? discCheckStatus = inputFormat.VerifyMediaImage();
|
|
|
|
|
DateTime endCheck = DateTime.UtcNow;
|
|
|
|
|
|
|
|
|
|
TimeSpan checkTime = endCheck - startCheck;
|
|
|
|
|
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
lblImageResult.Visible = true;
|
|
|
|
|
switch(discCheckStatus)
|
|
|
|
|
{
|
|
|
|
|
case true:
|
|
|
|
|
lblImageResult.Text = "Disc image checksums are correct";
|
|
|
|
|
break;
|
|
|
|
|
case false:
|
|
|
|
|
lblImageResult.Text = "Disc image checksums are incorrect";
|
|
|
|
|
break;
|
|
|
|
|
case null:
|
|
|
|
|
lblImageResult.Text = "Disc image does not contain checksums";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
correctDisc = discCheckStatus;
|
|
|
|
|
DicConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(chkVerifySectors.Checked == true)
|
|
|
|
|
{
|
|
|
|
|
DateTime startCheck;
|
|
|
|
|
DateTime endCheck;
|
|
|
|
|
List<ulong> failingLbas = new List<ulong>();
|
|
|
|
|
List<ulong> unknownLbas = new List<ulong>();
|
|
|
|
|
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
lblProgress2.Visible = true;
|
|
|
|
|
prgProgress2.Indeterminate = false;
|
|
|
|
|
prgProgress2.MaxValue = (int)(inputFormat.Info.Sectors / 512);
|
|
|
|
|
btnStop.Enabled = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if(formatHasTracks)
|
|
|
|
|
{
|
|
|
|
|
List<Track> inputTracks = inputFormat.Tracks;
|
|
|
|
|
ulong currentSectorAll = 0;
|
|
|
|
|
|
|
|
|
|
startCheck = DateTime.UtcNow;
|
|
|
|
|
foreach(Track currentTrack in inputFormat.Tracks)
|
|
|
|
|
{
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
lblProgress.Text =
|
|
|
|
|
$"Verifying track {currentTrack.TrackSequence} of {inputFormat.Tracks.Count}";
|
|
|
|
|
prgProgress.Value++;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector;
|
|
|
|
|
ulong currentSector = 0;
|
|
|
|
|
|
|
|
|
|
while(remainingSectors > 0)
|
|
|
|
|
{
|
|
|
|
|
if(cancel)
|
|
|
|
|
{
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
btnClose.Visible = true;
|
|
|
|
|
btnStart.Visible = false;
|
|
|
|
|
btnStop.Visible = false;
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ulong all = currentSectorAll;
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
prgProgress2.Value = (int)(all / 512);
|
|
|
|
|
lblProgress2.Text =
|
|
|
|
|
$"Checking sector {all} of {inputFormat.Info.Sectors}, on track {currentTrack.TrackSequence}";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
List<ulong> tempfailingLbas;
|
|
|
|
|
List<ulong> tempunknownLbas;
|
|
|
|
|
|
|
|
|
|
if(remainingSectors < 512)
|
|
|
|
|
inputFormat.VerifySectors(currentSector, (uint)remainingSectors,
|
|
|
|
|
currentTrack.TrackSequence, out tempfailingLbas,
|
|
|
|
|
out tempunknownLbas);
|
|
|
|
|
else
|
|
|
|
|
inputFormat.VerifySectors(currentSector, 512, currentTrack.TrackSequence,
|
|
|
|
|
out tempfailingLbas, out tempunknownLbas);
|
|
|
|
|
|
|
|
|
|
failingLbas.AddRange(tempfailingLbas);
|
|
|
|
|
|
|
|
|
|
unknownLbas.AddRange(tempunknownLbas);
|
|
|
|
|
|
|
|
|
|
if(remainingSectors < 512)
|
|
|
|
|
{
|
|
|
|
|
currentSector += remainingSectors;
|
|
|
|
|
currentSectorAll += remainingSectors;
|
|
|
|
|
remainingSectors = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
currentSector += 512;
|
|
|
|
|
currentSectorAll += 512;
|
|
|
|
|
remainingSectors -= 512;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
endCheck = DateTime.UtcNow;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ulong remainingSectors = inputFormat.Info.Sectors;
|
|
|
|
|
ulong currentSector = 0;
|
|
|
|
|
|
|
|
|
|
startCheck = DateTime.UtcNow;
|
|
|
|
|
while(remainingSectors > 0)
|
|
|
|
|
{
|
|
|
|
|
if(cancel)
|
|
|
|
|
{
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
btnClose.Visible = true;
|
|
|
|
|
btnStart.Visible = false;
|
|
|
|
|
btnStop.Visible = false;
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ulong sector = currentSector;
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
prgProgress2.Value = (int)(sector / 512);
|
|
|
|
|
lblProgress2.Text = $"Checking sector {sector} of {inputFormat.Info.Sectors}";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
List<ulong> tempfailingLbas;
|
|
|
|
|
List<ulong> tempunknownLbas;
|
|
|
|
|
|
|
|
|
|
if(remainingSectors < 512)
|
|
|
|
|
inputFormat.VerifySectors(currentSector, (uint)remainingSectors, out tempfailingLbas,
|
|
|
|
|
out tempunknownLbas);
|
|
|
|
|
else inputFormat.VerifySectors(currentSector, 512, out tempfailingLbas, out tempunknownLbas);
|
|
|
|
|
|
|
|
|
|
failingLbas.AddRange(tempfailingLbas);
|
|
|
|
|
|
|
|
|
|
unknownLbas.AddRange(tempunknownLbas);
|
|
|
|
|
|
|
|
|
|
if(remainingSectors < 512)
|
|
|
|
|
{
|
|
|
|
|
currentSector += remainingSectors;
|
|
|
|
|
remainingSectors = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
currentSector += 512;
|
|
|
|
|
remainingSectors -= 512;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
endCheck = DateTime.UtcNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TimeSpan checkTime = endCheck - startCheck;
|
|
|
|
|
|
|
|
|
|
DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds);
|
|
|
|
|
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
if(failingLbas.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
if(failingLbas.Count == (int)inputFormat.Info.Sectors)
|
|
|
|
|
{
|
|
|
|
|
lblSectorsErrorsAll.Visible = true;
|
|
|
|
|
lblSectorsErrorsAll.Text = "All sectors contain errors";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
grpSectorErrors.Text = "LBAs with error:";
|
|
|
|
|
grpSectorErrors.Visible = true;
|
|
|
|
|
|
|
|
|
|
TreeGridItemCollection errorList = new TreeGridItemCollection();
|
|
|
|
|
|
|
|
|
|
treeSectorErrors.Columns.Add(new GridColumn
|
|
|
|
|
{
|
|
|
|
|
HeaderText = "LBA", DataCell = new TextBoxCell(0)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
treeSectorErrors.AllowMultipleSelection = false;
|
|
|
|
|
treeSectorErrors.ShowHeader = false;
|
|
|
|
|
treeSectorErrors.DataStore = errorList;
|
|
|
|
|
|
|
|
|
|
foreach(ulong t in failingLbas) errorList.Add(new TreeGridItem {Values = new object[] {t}});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(unknownLbas.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
if(unknownLbas.Count == (int)inputFormat.Info.Sectors)
|
|
|
|
|
{
|
|
|
|
|
lblSectorsErrorsAll.Visible = true;
|
|
|
|
|
lblSectorsErrorsAll.Text = "All sectors contain errors";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
grpSectorsUnknowns.Text = "LBAs with error:";
|
|
|
|
|
grpSectorsUnknowns.Visible = true;
|
|
|
|
|
|
|
|
|
|
TreeGridItemCollection unknownList = new TreeGridItemCollection();
|
|
|
|
|
|
|
|
|
|
treeSectorsUnknowns.Columns.Add(new GridColumn
|
|
|
|
|
{
|
|
|
|
|
HeaderText = "LBA", DataCell = new TextBoxCell(0)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
treeSectorsUnknowns.AllowMultipleSelection = false;
|
|
|
|
|
treeSectorsUnknowns.ShowHeader = false;
|
|
|
|
|
treeSectorsUnknowns.DataStore = unknownList;
|
|
|
|
|
|
|
|
|
|
foreach(ulong t in unknownLbas)
|
|
|
|
|
unknownList.Add(new TreeGridItem {Values = new object[] {t}});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
grpSectorSummary.Visible = true;
|
|
|
|
|
lblTotalSectors.Text = $"Total sectors........... {inputFormat.Info.Sectors}";
|
|
|
|
|
lblTotalSectorErrors.Text = $"Total errors............ {failingLbas.Count}";
|
|
|
|
|
lblTotalSectorUnknowns.Text = $"Total unknowns.......... {unknownLbas.Count}";
|
|
|
|
|
lblTotalSectorErrorsUnknowns.Text =
|
|
|
|
|
$"Total errors+unknowns... {failingLbas.Count + unknownLbas.Count}";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
totalSectors = (long)inputFormat.Info.Sectors;
|
|
|
|
|
errorSectors = failingLbas.Count;
|
|
|
|
|
unknownSectors = unknownLbas.Count;
|
|
|
|
|
correctSectors = totalSectors - errorSectors - unknownSectors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Statistics.AddCommand("verify");
|
|
|
|
|
|
|
|
|
|
Application.Instance.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
stkOptions.Visible = false;
|
|
|
|
|
stkResults.Visible = true;
|
|
|
|
|
stkProgress.Visible = false;
|
|
|
|
|
btnStart.Visible = false;
|
|
|
|
|
btnStop.Visible = false;
|
|
|
|
|
btnClose.Visible = true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void OnBtnClose(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void OnBtnStop(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
cancel = true;
|
|
|
|
|
btnStop.Enabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region XAML IDs
|
|
|
|
|
StackLayout stkOptions;
|
|
|
|
|
CheckBox chkVerifyImage;
|
|
|
|
|
CheckBox chkVerifySectors;
|
|
|
|
|
StackLayout stkResults;
|
|
|
|
|
StackLayout stkSectorResults;
|
|
|
|
|
StackLayout stkSectorErrors;
|
|
|
|
|
GroupBox grpSectorErrors;
|
|
|
|
|
TreeGridView treeSectorErrors;
|
|
|
|
|
StackLayout stkSectorUnknowns;
|
|
|
|
|
GroupBox grpSectorsUnknowns;
|
|
|
|
|
TreeGridView treeSectorsUnknowns;
|
|
|
|
|
Label lblImageResult;
|
|
|
|
|
Label lblSectorsErrorsAll;
|
|
|
|
|
Label lblSectorsUnknownAll;
|
|
|
|
|
GroupBox grpSectorSummary;
|
|
|
|
|
Label lblTotalSectors;
|
|
|
|
|
Label lblTotalSectorErrors;
|
|
|
|
|
Label lblTotalSectorUnknowns;
|
|
|
|
|
Label lblTotalSectorErrorsUnknowns;
|
|
|
|
|
StackLayout stkProgress;
|
|
|
|
|
StackLayout stkProgress1;
|
|
|
|
|
Label lblProgress;
|
|
|
|
|
ProgressBar prgProgress;
|
|
|
|
|
StackLayout stkProgress2;
|
|
|
|
|
Label lblProgress2;
|
|
|
|
|
ProgressBar prgProgress2;
|
|
|
|
|
Button btnStart;
|
|
|
|
|
Button btnClose;
|
|
|
|
|
Button btnStop;
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|