Files
Aaru/Aaru.Core/Sidecar/BlockMedia.cs

1263 lines
51 KiB
C#
Raw Normal View History

2017-08-08 13:40:32 +01:00
// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
2017-08-08 13:40:32 +01:00
// ----------------------------------------------------------------------------
//
// Filename : BlockMedia.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
2017-08-08 13:40:32 +01:00
//
// Component : Core algorithms.
2017-08-08 13:40:32 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
// Contains logic to create sidecar from a block media dump.
2017-08-08 13:40:32 +01:00
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
2022-12-03 16:07:10 +00:00
// Copyright © 2011-2023 Natalia Portillo
2017-08-08 13:40:32 +01:00
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs;
2020-02-29 18:03:35 +00:00
using Aaru.CommonTypes.Structs.Devices.ATA;
2020-02-27 00:33:26 +00:00
using Aaru.Console;
using Aaru.Decoders.PCMCIA;
using Aaru.DiscImages;
using Aaru.Filters;
using Aaru.Helpers;
2017-08-08 13:40:32 +01:00
using Schemas;
2020-02-27 00:33:26 +00:00
using MediaType = Aaru.CommonTypes.Metadata.MediaType;
using Tuple = Aaru.Decoders.PCMCIA.Tuple;
2017-08-08 13:40:32 +01:00
namespace Aaru.Core;
2022-03-06 13:29:38 +00:00
public sealed partial class Sidecar
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
/// <summary>Creates a metadata sidecar for a block media (e.g. floppy, hard disk, flash card, usb stick)</summary>
/// <param name="image">Image</param>
/// <param name="filterId">Filter uuid</param>
/// <param name="imagePath">Image path</param>
/// <param name="fi">Image file information</param>
/// <param name="plugins">Image plugins</param>
/// <param name="imgChecksums">List of image checksums</param>
/// <param name="sidecar">Metadata sidecar</param>
/// <param name="encoding">Encoding to be used for filesystem plugins</param>
void BlockMedia(IMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins,
List<ChecksumType> imgChecksums, ref CICMMetadataType sidecar, Encoding encoding)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia = new[]
{
new BlockMediaType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Checksums = imgChecksums.ToArray(),
Image = new ImageType
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
format = image.Format,
offset = 0,
offsetSpecified = true,
Value = Path.GetFileName(imagePath)
},
Size = (ulong)fi.Length,
Sequence = new SequenceType
{
MediaTitle = image.Info.MediaTitle
2017-08-08 14:18:31 +01:00
}
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
};
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(image.Info.MediaSequence != 0 &&
image.Info.LastMediaSequence != 0)
{
sidecar.BlockMedia[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence;
sidecar.BlockMedia[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence;
}
else
{
sidecar.BlockMedia[0].Sequence.MediaSequence = 1;
sidecar.BlockMedia[0].Sequence.TotalMedia = 1;
}
2019-04-20 19:21:00 +01:00
UpdateStatus(Localization.Core.Hashing_media_tags);
2022-03-06 13:29:38 +00:00
ErrorNumber errno;
byte[] buffer;
2022-03-06 13:29:38 +00:00
foreach(MediaTagType tagType in image.Info.ReadableMediaTags)
{
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
switch(tagType)
{
case MediaTagType.ATAPI_IDENTIFY:
errno = image.ReadMediaTag(MediaTagType.ATAPI_IDENTIFY, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].ATA = new ATAType
{
Identify = new DumpType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
}
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.ATA_IDENTIFY:
errno = image.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].ATA = new ATAType
{
Identify = new DumpType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
}
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.PCMCIA_CIS:
errno = image.ReadMediaTag(MediaTagType.PCMCIA_CIS, out byte[] cis);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
{
CIS = new DumpType
{
Checksums = Checksum.GetChecksums(cis).ToArray(),
Size = (ulong)cis.Length
}
};
2022-03-06 13:29:38 +00:00
Tuple[] tuples = CIS.GetTuples(cis);
2022-03-06 13:29:38 +00:00
if(tuples != null)
foreach(Tuple tuple in tuples)
switch(tuple.Code)
{
case TupleCodes.CISTPL_MANFID:
ManufacturerIdentificationTuple manfid =
CIS.DecodeManufacturerIdentificationTuple(tuple);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(manfid != null)
{
sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = manfid.ManufacturerID;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID;
sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
}
2022-03-06 13:29:38 +00:00
break;
case TupleCodes.CISTPL_VERS_1:
Level1VersionTuple vers = CIS.DecodeLevel1VersionTuple(tuple);
2022-03-06 13:29:38 +00:00
if(vers != null)
{
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].PCMCIA.Compliance =
$"{vers.MajorVersion}.{vers.MinorVersion}";
2022-03-07 07:36:44 +00:00
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = vers.AdditionalInformation;
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
break;
2017-08-08 14:18:31 +01:00
}
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SCSI_INQUIRY:
errno = image.ReadMediaTag(MediaTagType.SCSI_INQUIRY, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SCSI = new SCSIType
{
Inquiry = new DumpType
2017-08-08 14:18:31 +01:00
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
2022-03-06 13:29:38 +00:00
}
};
break;
case MediaTagType.SD_CID:
errno = image.ReadMediaTag(MediaTagType.SD_CID, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital.CID = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SD_CSD:
errno = image.ReadMediaTag(MediaTagType.SD_CSD, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SD_SCR:
errno = image.ReadMediaTag(MediaTagType.SD_SCR, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-09-29 14:43:59 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SD_OCR:
errno = image.ReadMediaTag(MediaTagType.SD_OCR, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-09-29 14:43:59 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital ??= new SecureDigitalType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SecureDigital.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.MMC_CID:
errno = image.ReadMediaTag(MediaTagType.MMC_CID, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-09-29 14:43:59 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard.CID = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.MMC_CSD:
errno = image.ReadMediaTag(MediaTagType.MMC_CSD, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-09-29 14:43:59 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.MMC_OCR:
errno = image.ReadMediaTag(MediaTagType.MMC_OCR, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-09-29 14:43:59 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.MMC_ExtendedCSD:
errno = image.ReadMediaTag(MediaTagType.MMC_ExtendedCSD, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard ??= new MultiMediaCardType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.USB_Descriptors:
errno = image.ReadMediaTag(MediaTagType.USB_Descriptors, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].USB ??= new USBType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].USB.Descriptors = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SCSI_MODESENSE_6:
errno = image.ReadMediaTag(MediaTagType.SCSI_MODESENSE_6, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SCSI ??= new SCSIType();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SCSI.ModeSense = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.SCSI_MODESENSE_10:
errno = image.ReadMediaTag(MediaTagType.SCSI_MODESENSE_10, out buffer);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
break;
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].SCSI ??= new SCSIType();
sidecar.BlockMedia[0].SCSI.ModeSense10 = new DumpType
{
Checksums = Checksum.GetChecksums(buffer).ToArray(),
Size = (ulong)buffer.Length
};
break;
2019-04-20 19:21:00 +01:00
}
2022-03-06 13:29:38 +00:00
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") &&
filterId == new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
sidecar.BlockMedia[0].ContentChecksums = sidecar.BlockMedia[0].Checksums;
else
{
UpdateStatus(Localization.Core.Hashing_sectors);
2022-03-06 13:29:38 +00:00
var contentChkWorker = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
const uint sectorsToRead = 64;
ulong sectors = image.Info.Sectors;
ulong doneSectors = 0;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
InitProgress2();
2022-03-06 13:29:38 +00:00
while(doneSectors < sectors)
{
if(_aborted)
{
EndProgress2();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
return;
}
byte[] sector;
2022-03-06 13:29:38 +00:00
if(sectors - doneSectors >= sectorsToRead)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
errno = image.ReadSectors(doneSectors, sectorsToRead, out sector);
if(errno != ErrorNumber.NoError)
2019-04-20 19:21:00 +01:00
{
UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors));
2019-04-20 19:21:00 +01:00
EndProgress2();
2019-04-20 19:21:00 +01:00
return;
}
UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, (long)doneSectors, (long)sectors);
2022-03-06 13:29:38 +00:00
doneSectors += sectorsToRead;
}
else
{
errno = image.ReadSectors(doneSectors, (uint)(sectors - doneSectors), out sector);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
{
UpdateStatus(string.Format(Localization.Core.Error_0_reading_sector_1, errno, doneSectors));
2022-03-06 13:29:38 +00:00
EndProgress2();
return;
}
UpdateProgress2(Localization.Core.Hashing_sector_0_of_1, (long)doneSectors, (long)sectors);
2022-03-06 13:29:38 +00:00
doneSectors += sectors - doneSectors;
}
contentChkWorker.Update(sector);
}
// For fast debugging, skip checksum
//skipImageChecksum:
List<ChecksumType> cntChecksums = contentChkWorker.End();
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].ContentChecksums = cntChecksums.ToArray();
EndProgress2();
}
(string type, string subType) diskType = MediaType.MediaTypeToString(image.Info.MediaType);
sidecar.BlockMedia[0].DiskType = diskType.type;
sidecar.BlockMedia[0].DiskSubType = diskType.subType;
Statistics.AddMedia(image.Info.MediaType, false);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType);
sidecar.BlockMedia[0].LogicalBlocks = image.Info.Sectors;
sidecar.BlockMedia[0].LogicalBlockSize = image.Info.SectorSize;
// TODO: Detect it
sidecar.BlockMedia[0].PhysicalBlockSize = image.Info.SectorSize;
if(image is ITapeImage { IsTape: true } tapeImage)
{
List<TapePartitionType> tapePartitions = new();
foreach(TapePartition tapePartition in tapeImage.TapePartitions)
{
var thisPartition = new TapePartitionType
{
Image = sidecar.BlockMedia[0].Image,
Sequence = tapePartition.Number,
StartBlock = tapePartition.FirstBlock,
EndBlock = tapePartition.LastBlock
};
if(tapeImage.TapePartitions.Count == 1)
thisPartition.Checksums = sidecar.BlockMedia[0].ContentChecksums;
else
{
UpdateStatus(string.Format(Localization.Core.Hashing_partition_0, tapePartition.Number));
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
var tapePartitionChk = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
const uint sectorsToRead = 64;
ulong sectors = tapePartition.LastBlock - tapePartition.FirstBlock + 1;
ulong doneSectors = 0;
2022-03-06 13:29:38 +00:00
InitProgress2();
while(doneSectors < sectors)
{
if(_aborted)
{
EndProgress2();
return;
}
2022-03-06 13:29:38 +00:00
byte[] sector;
2022-03-06 13:29:38 +00:00
if(sectors - doneSectors >= sectorsToRead)
{
2022-03-06 13:29:38 +00:00
errno = image.ReadSectors(tapePartition.FirstBlock + doneSectors, sectorsToRead,
out sector);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1,
errno,
tapePartition.FirstBlock + doneSectors));
2022-03-06 13:29:38 +00:00
EndProgress2();
return;
}
UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors, (long)sectors);
2022-03-06 13:29:38 +00:00
doneSectors += sectorsToRead;
}
2022-03-06 13:29:38 +00:00
else
{
errno = image.ReadSectors(tapePartition.FirstBlock + doneSectors,
(uint)(sectors - doneSectors), out sector);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1,
errno,
tapePartition.FirstBlock + doneSectors));
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
EndProgress2();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
return;
}
UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors, (long)sectors);
2022-03-06 13:29:38 +00:00
doneSectors += sectors - doneSectors;
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
thisPartition.Size += (ulong)sector.LongLength;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
tapePartitionChk.Update(sector);
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
// For fast debugging, skip checksum
//skipImageChecksum:
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
List<ChecksumType> partitionChecksums = tapePartitionChk.End();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
thisPartition.Checksums = partitionChecksums.ToArray();
2022-03-06 13:29:38 +00:00
EndProgress2();
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
List<TapeFileType> filesInPartition = new();
2022-03-06 13:29:38 +00:00
foreach(TapeFile tapeFile in tapeImage.Files.Where(f => f.Partition == tapePartition.Number))
2019-05-02 18:50:16 +01:00
{
2022-03-06 13:29:38 +00:00
var thisFile = new TapeFileType
2019-05-02 18:50:16 +01:00
{
2022-03-06 13:29:38 +00:00
Sequence = tapeFile.File,
StartBlock = tapeFile.FirstBlock,
EndBlock = tapeFile.LastBlock,
2020-07-20 04:34:16 +01:00
Image = sidecar.BlockMedia[0].Image,
2022-03-06 13:29:38 +00:00
Size = 0,
BlockSize = 0
2019-05-02 18:50:16 +01:00
};
2022-03-06 13:29:38 +00:00
if(tapeImage.Files.Count(f => f.Partition == tapePartition.Number) == 1)
{
thisFile.Checksums = thisPartition.Checksums;
thisFile.Size = thisPartition.Size;
}
2019-05-02 18:50:16 +01:00
else
{
UpdateStatus(string.Format(Localization.Core.Hashing_file_0, tapeFile.File));
2019-05-02 18:50:16 +01:00
2020-07-20 21:11:32 +01:00
if(_aborted)
return;
2019-05-02 18:50:16 +01:00
2022-03-06 13:29:38 +00:00
var tapeFileChk = new Checksum();
2019-05-02 18:50:16 +01:00
// For fast debugging, skip checksum
//goto skipImageChecksum;
const uint sectorsToRead = 64;
ulong sectors = tapeFile.LastBlock - tapeFile.FirstBlock + 1;
ulong doneSectors = 0;
2019-05-02 18:50:16 +01:00
InitProgress2();
2019-05-02 18:50:16 +01:00
while(doneSectors < sectors)
{
2020-07-20 21:11:32 +01:00
if(_aborted)
2019-05-02 18:50:16 +01:00
{
EndProgress2();
2019-05-02 18:50:16 +01:00
return;
}
byte[] sector;
if(sectors - doneSectors >= sectorsToRead)
{
2022-03-07 07:36:44 +00:00
errno = image.ReadSectors(tapeFile.FirstBlock + doneSectors, sectorsToRead, out sector);
if(errno != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1,
errno, tapeFile.FirstBlock + doneSectors));
EndProgress2();
return;
}
UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors,
(long)sectors);
2019-05-02 18:50:16 +01:00
doneSectors += sectorsToRead;
}
else
{
2022-03-06 13:29:38 +00:00
errno = image.ReadSectors(tapeFile.FirstBlock + doneSectors,
(uint)(sectors - doneSectors), out sector);
if(errno != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine(string.Format(Localization.Core.Error_0_reading_sector_1,
errno, tapeFile.FirstBlock + doneSectors));
EndProgress2();
return;
}
UpdateProgress2(Localization.Core.Hashing_blocks_0_of_1, (long)doneSectors,
(long)sectors);
2019-05-02 18:50:16 +01:00
doneSectors += sectors - doneSectors;
}
2022-03-06 13:29:38 +00:00
if((ulong)sector.LongLength > thisFile.BlockSize)
thisFile.BlockSize = (ulong)sector.LongLength;
thisFile.Size += (ulong)sector.LongLength;
2019-05-02 18:50:16 +01:00
2022-03-06 13:29:38 +00:00
tapeFileChk.Update(sector);
2019-05-02 18:50:16 +01:00
}
// For fast debugging, skip checksum
//skipImageChecksum:
2022-03-06 13:29:38 +00:00
List<ChecksumType> fileChecksums = tapeFileChk.End();
2019-05-02 18:50:16 +01:00
2022-03-06 13:29:38 +00:00
thisFile.Checksums = fileChecksums.ToArray();
2019-05-02 18:50:16 +01:00
EndProgress2();
}
2022-03-06 13:29:38 +00:00
filesInPartition.Add(thisFile);
2019-05-02 18:50:16 +01:00
}
2022-03-06 13:29:38 +00:00
thisPartition.File = filesInPartition.ToArray();
tapePartitions.Add(thisPartition);
2019-05-02 18:50:16 +01:00
}
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].TapeInformation = tapePartitions.ToArray();
}
2019-04-20 19:21:00 +01:00
UpdateStatus(Localization.Core.Checking_filesystems);
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
List<Partition> partitions = Partitions.GetAll(image);
Partitions.AddSchemesToStats(partitions);
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[1];
2022-03-06 13:29:38 +00:00
if(partitions.Count > 0)
{
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[partitions.Count];
2017-08-08 13:40:32 +01:00
for(int i = 0; i < partitions.Count; i++)
2017-08-08 13:40:32 +01:00
{
2020-07-20 21:11:32 +01:00
if(_aborted)
return;
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].FileSystemInformation[i] = new PartitionType
{
2022-03-06 13:29:38 +00:00
Description = partitions[i].Description,
EndSector = partitions[i].End,
Name = partitions[i].Name,
Sequence = (uint)partitions[i].Sequence,
StartSector = partitions[i].Start,
Type = partitions[i].Type
2017-08-08 13:40:32 +01:00
};
List<FileSystemType> lstFs = new();
2017-08-08 13:40:32 +01:00
foreach(IFilesystem plugin in plugins.PluginsList.Values)
2017-08-08 13:40:32 +01:00
try
{
2020-07-20 21:11:32 +01:00
if(_aborted)
return;
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
if(!plugin.Identify(image, partitions[i]))
continue;
if(plugin is IReadOnlyFilesystem fsPlugin &&
2022-03-06 13:29:38 +00:00
fsPlugin.Mount(image, partitions[i], encoding, null, null) == ErrorNumber.NoError)
{
UpdateStatus(string.Format(Localization.Core.Mounting_0, fsPlugin.XmlFsType.Type));
fsPlugin.XmlFsType.Contents = Files(fsPlugin);
fsPlugin.Unmount();
}
else
2022-03-06 13:29:38 +00:00
plugin.GetInformation(image, partitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
2017-08-08 13:40:32 +01:00
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
{
2020-02-27 23:48:41 +00:00
//AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
2017-08-08 13:40:32 +01:00
}
if(lstFs.Count > 0)
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray();
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
}
else
{
if(_aborted)
return;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].FileSystemInformation[0] = new PartitionType
{
2022-03-06 13:29:38 +00:00
StartSector = 0,
EndSector = image.Info.Sectors - 1
};
2022-03-06 13:29:38 +00:00
var wholePart = new Partition
{
Name = Localization.Core.Whole_device,
2022-03-06 13:29:38 +00:00
Length = image.Info.Sectors,
Size = image.Info.Sectors * image.Info.SectorSize
};
2022-03-06 13:29:38 +00:00
List<FileSystemType> lstFs = new();
2022-03-06 13:29:38 +00:00
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(_aborted)
return;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(!plugin.Identify(image, wholePart))
continue;
2022-03-06 13:29:38 +00:00
if(plugin is IReadOnlyFilesystem fsPlugin &&
fsPlugin.Mount(image, wholePart, encoding, null, null) == ErrorNumber.NoError)
{
UpdateStatus(string.Format(Localization.Core.Mounting_0, fsPlugin.XmlFsType.Type));
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
fsPlugin.XmlFsType.Contents = Files(fsPlugin);
2022-03-06 13:29:38 +00:00
fsPlugin.Unmount();
}
else
plugin.GetInformation(image, wholePart, out _, encoding);
2022-03-06 13:29:38 +00:00
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
{
//AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
2022-03-06 13:29:38 +00:00
if(lstFs.Count > 0)
sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray();
}
UpdateStatus(Localization.Core.Saving_metadata);
if(image.Info.Cylinders > 0 &&
image.Info is { Heads: > 0, SectorsPerTrack: > 0 })
2022-03-06 13:29:38 +00:00
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = image.Info.Cylinders;
sidecar.BlockMedia[0].Heads = (ushort)image.Info.Heads;
sidecar.BlockMedia[0].SectorsPerTrack = image.Info.SectorsPerTrack;
}
2022-03-06 13:29:38 +00:00
if(image.Info.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
{
Identify.IdentifyDevice? ataId = null;
errno = image.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out buffer);
2022-03-06 13:29:38 +00:00
if(errno == ErrorNumber.NoError)
ataId = Identify.Decode(buffer);
2022-03-06 13:29:38 +00:00
if(ataId.HasValue)
if(ataId.Value.CurrentCylinders > 0 &&
ataId.Value.CurrentHeads > 0 &&
ataId.Value.CurrentSectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = ataId.Value.CurrentCylinders;
sidecar.BlockMedia[0].Heads = ataId.Value.CurrentHeads;
sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.CurrentSectorsPerTrack;
}
else if(ataId.Value.Cylinders > 0 &&
ataId.Value.Heads > 0 &&
ataId.Value.SectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = ataId.Value.Cylinders;
sidecar.BlockMedia[0].Heads = ataId.Value.Heads;
sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.SectorsPerTrack;
}
}
2022-03-06 13:29:38 +00:00
if(image.DumpHardware != null)
sidecar.BlockMedia[0].DumpHardwareArray = image.DumpHardware.ToArray();
2022-03-06 13:29:38 +00:00
// TODO: This is more of a hack, redo it planned for >4.0
string trkFormat = null;
2022-03-06 13:29:38 +00:00
switch(image.Info.MediaType)
{
case CommonTypes.MediaType.Apple32SS:
case CommonTypes.MediaType.Apple32DS:
trkFormat = "Apple GCR (DOS 3.2)";
break;
case CommonTypes.MediaType.Apple33SS:
case CommonTypes.MediaType.Apple33DS:
trkFormat = "Apple GCR (DOS 3.3)";
break;
case CommonTypes.MediaType.AppleSonySS:
case CommonTypes.MediaType.AppleSonyDS:
trkFormat = "Apple GCR (Sony)";
break;
case CommonTypes.MediaType.AppleFileWare:
trkFormat = "Apple GCR (Twiggy)";
break;
case CommonTypes.MediaType.DOS_525_SS_DD_9:
case CommonTypes.MediaType.DOS_525_DS_DD_8:
case CommonTypes.MediaType.DOS_525_DS_DD_9:
case CommonTypes.MediaType.DOS_525_HD:
case CommonTypes.MediaType.DOS_35_SS_DD_8:
case CommonTypes.MediaType.DOS_35_SS_DD_9:
case CommonTypes.MediaType.DOS_35_DS_DD_8:
case CommonTypes.MediaType.DOS_35_DS_DD_9:
case CommonTypes.MediaType.DOS_35_HD:
case CommonTypes.MediaType.DOS_35_ED:
case CommonTypes.MediaType.DMF:
case CommonTypes.MediaType.DMF_82:
case CommonTypes.MediaType.XDF_525:
case CommonTypes.MediaType.XDF_35:
case CommonTypes.MediaType.IBM53FD_256:
case CommonTypes.MediaType.IBM53FD_512:
case CommonTypes.MediaType.IBM53FD_1024:
case CommonTypes.MediaType.RX02:
case CommonTypes.MediaType.RX03:
case CommonTypes.MediaType.RX50:
case CommonTypes.MediaType.ACORN_525_SS_DD_40:
case CommonTypes.MediaType.ACORN_525_SS_DD_80:
case CommonTypes.MediaType.ACORN_525_DS_DD:
case CommonTypes.MediaType.ACORN_35_DS_DD:
case CommonTypes.MediaType.ACORN_35_DS_HD:
case CommonTypes.MediaType.ATARI_525_ED:
case CommonTypes.MediaType.ATARI_525_DD:
case CommonTypes.MediaType.ATARI_35_SS_DD:
case CommonTypes.MediaType.ATARI_35_DS_DD:
case CommonTypes.MediaType.ATARI_35_SS_DD_11:
case CommonTypes.MediaType.ATARI_35_DS_DD_11:
case CommonTypes.MediaType.DOS_525_SS_DD_8:
case CommonTypes.MediaType.NEC_8_DD:
case CommonTypes.MediaType.NEC_525_SS:
case CommonTypes.MediaType.NEC_525_DS:
case CommonTypes.MediaType.NEC_525_HD:
case CommonTypes.MediaType.NEC_35_HD_8:
case CommonTypes.MediaType.NEC_35_HD_15:
case CommonTypes.MediaType.NEC_35_TD:
case CommonTypes.MediaType.FDFORMAT_525_DD:
case CommonTypes.MediaType.FDFORMAT_525_HD:
case CommonTypes.MediaType.FDFORMAT_35_DD:
case CommonTypes.MediaType.FDFORMAT_35_HD:
case CommonTypes.MediaType.Apricot_35:
case CommonTypes.MediaType.CompactFloppy:
case CommonTypes.MediaType.MetaFloppy_Mod_I:
case CommonTypes.MediaType.MetaFloppy_Mod_II:
trkFormat = "IBM MFM";
break;
case CommonTypes.MediaType.ATARI_525_SD:
case CommonTypes.MediaType.NEC_8_SD:
case CommonTypes.MediaType.ACORN_525_SS_SD_40:
case CommonTypes.MediaType.ACORN_525_SS_SD_80:
case CommonTypes.MediaType.RX01:
case CommonTypes.MediaType.IBM23FD:
case CommonTypes.MediaType.IBM33FD_128:
case CommonTypes.MediaType.IBM33FD_256:
case CommonTypes.MediaType.IBM33FD_512:
case CommonTypes.MediaType.IBM43FD_128:
case CommonTypes.MediaType.IBM43FD_256:
trkFormat = "IBM FM";
break;
case CommonTypes.MediaType.CBM_35_DD:
trkFormat = "Commodore MFM";
break;
case CommonTypes.MediaType.CBM_AMIGA_35_HD:
case CommonTypes.MediaType.CBM_AMIGA_35_DD:
trkFormat = "Amiga MFM";
break;
case CommonTypes.MediaType.CBM_1540:
case CommonTypes.MediaType.CBM_1540_Ext:
case CommonTypes.MediaType.CBM_1571:
trkFormat = "Commodore GCR";
break;
case CommonTypes.MediaType.SHARP_525_9:
case CommonTypes.MediaType.SHARP_35_9: break;
case CommonTypes.MediaType.ECMA_99_15:
case CommonTypes.MediaType.ECMA_99_26:
case CommonTypes.MediaType.ECMA_99_8:
trkFormat = "ISO MFM";
break;
case CommonTypes.MediaType.ECMA_54:
case CommonTypes.MediaType.ECMA_59:
case CommonTypes.MediaType.ECMA_66:
case CommonTypes.MediaType.ECMA_69_8:
case CommonTypes.MediaType.ECMA_69_15:
case CommonTypes.MediaType.ECMA_69_26:
case CommonTypes.MediaType.ECMA_70:
case CommonTypes.MediaType.ECMA_78:
case CommonTypes.MediaType.ECMA_78_2:
trkFormat = "ISO FM";
break;
default:
trkFormat = "Unknown";
break;
}
2022-03-06 13:29:38 +00:00
#region SuperCardPro
string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
Path.GetFileNameWithoutExtension(imagePath) + ".scp");
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
if(File.Exists(scpFilePath))
{
UpdateStatus(Localization.Core.Hashing_SuperCardPro_image);
2022-03-06 13:29:38 +00:00
var scpImage = new SuperCardPro();
var scpFilter = new ZZZNoFilter();
scpFilter.Open(scpFilePath);
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
if(image.Info.Heads <= 2 &&
scpImage.Identify(scpFilter))
{
2022-03-06 13:29:38 +00:00
try
{
2022-03-06 13:29:38 +00:00
scpImage.Open(scpFilter);
}
catch(NotImplementedException) {}
if((image.Info.Heads == 2 && scpImage.Header.heads == 0) ||
(image.Info.Heads == 1 && scpImage.Header.heads is 1 or 2))
2022-03-06 13:29:38 +00:00
if(scpImage.Header.end + 1 >= image.Info.Cylinders)
{
2022-03-06 13:29:38 +00:00
List<BlockTrackType> scpBlockTrackTypes = new();
ulong currentSector = 0;
Stream scpStream = scpFilter.GetDataForkStream();
2022-03-06 13:29:38 +00:00
for(byte t = scpImage.Header.start; t <= scpImage.Header.end; t++)
{
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
var scpBlockTrackType = new BlockTrackType
{
2022-03-06 13:29:38 +00:00
Cylinder = t / image.Info.Heads,
Head = (ushort)(t % image.Info.Heads),
Image = new ImageType
{
2022-03-06 13:29:38 +00:00
format = scpImage.Format,
Value = Path.GetFileName(scpFilePath),
offset = scpImage.Header.offsets[t]
}
2022-03-06 13:29:38 +00:00
};
2022-03-06 13:29:38 +00:00
if(scpBlockTrackType.Cylinder < image.Info.Cylinders)
{
scpBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
scpBlockTrackType.EndSector = currentSector - 1;
scpBlockTrackType.Sectors = image.Info.SectorsPerTrack;
scpBlockTrackType.BytesPerSector = image.Info.SectorSize;
scpBlockTrackType.Format = trkFormat;
}
2022-03-06 13:29:38 +00:00
if(scpImage.ScpTracks.TryGetValue(t, out SuperCardPro.TrackHeader scpTrack))
{
byte[] trackContents =
2022-03-07 07:36:44 +00:00
new byte[scpTrack.Entries.Last().dataOffset + scpTrack.Entries.Last().trackLength -
scpImage.Header.offsets[t] + 1];
2022-03-06 13:29:38 +00:00
scpStream.Position = scpImage.Header.offsets[t];
scpStream.EnsureRead(trackContents, 0, trackContents.Length);
2022-03-06 13:29:38 +00:00
scpBlockTrackType.Size = (ulong)trackContents.Length;
scpBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
}
2022-03-06 13:29:38 +00:00
scpBlockTrackTypes.Add(scpBlockTrackType);
}
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].Track = scpBlockTrackTypes.OrderBy(t => t.Cylinder).
ThenBy(t => t.Head).ToArray();
}
else
2020-02-27 23:48:41 +00:00
AaruConsole.
ErrorWriteLine(Localization.Core.SCP_image_do_not_same_number_tracks_0_disk_image_1_ignoring,
2022-03-06 13:29:38 +00:00
scpImage.Header.end + 1, image.Info.Cylinders);
else
AaruConsole.
ErrorWriteLine(Localization.Core.SCP_image_do_not_same_number_heads_0_disk_image_1_ignoring, 2,
image.Info.Heads);
}
2022-03-06 13:29:38 +00:00
}
#endregion
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
#region KryoFlux
string kfFile = null;
2022-03-07 07:36:44 +00:00
string basename = Path.Combine(Path.GetDirectoryName(imagePath), Path.GetFileNameWithoutExtension(imagePath));
bool kfDir = false;
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
if(Directory.Exists(basename))
{
string[] possibleKfStarts = Directory.GetFiles(basename, "*.raw", SearchOption.TopDirectoryOnly);
2022-03-06 13:29:38 +00:00
if(possibleKfStarts.Length > 0)
{
kfFile = possibleKfStarts[0];
kfDir = true;
}
2022-03-06 13:29:38 +00:00
}
else if(File.Exists(basename + "00.0.raw"))
kfFile = basename + "00.0.raw";
else if(File.Exists(basename + "00.1.raw"))
kfFile = basename + "00.1.raw";
2022-03-06 13:29:38 +00:00
if(kfFile != null)
{
UpdateStatus(Localization.Core.Hashing_KryoFlux_images);
2022-03-06 13:29:38 +00:00
var kfImage = new KryoFlux();
var kfFilter = new ZZZNoFilter();
kfFilter.Open(kfFile);
2022-03-06 13:29:38 +00:00
if(image.Info.Heads <= 2 &&
kfImage.Identify(kfFilter))
{
try
{
2022-03-06 13:29:38 +00:00
kfImage.Open(kfFilter);
}
catch(NotImplementedException) {}
if(kfImage.Info.Heads == image.Info.Heads)
if(kfImage.Info.Cylinders >= image.Info.Cylinders)
{
2022-03-06 13:29:38 +00:00
List<BlockTrackType> kfBlockTrackTypes = new();
2022-03-06 13:29:38 +00:00
ulong currentSector = 0;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
foreach(KeyValuePair<byte, IFilter> kvp in kfImage.tracks)
{
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
var kfBlockTrackType = new BlockTrackType
{
2022-03-06 13:29:38 +00:00
Cylinder = kvp.Key / image.Info.Heads,
Head = (ushort)(kvp.Key % image.Info.Heads),
Image = new ImageType
{
2022-03-06 13:29:38 +00:00
format = kfImage.Format,
Value = kfDir
? Path.
Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.BasePath)),
kvp.Value.Filename) : kvp.Value.Filename,
offset = 0
}
2022-03-06 13:29:38 +00:00
};
2022-03-06 13:29:38 +00:00
if(kfBlockTrackType.Cylinder < image.Info.Cylinders)
{
kfBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
kfBlockTrackType.EndSector = currentSector - 1;
kfBlockTrackType.Sectors = image.Info.SectorsPerTrack;
kfBlockTrackType.BytesPerSector = image.Info.SectorSize;
kfBlockTrackType.Format = trkFormat;
}
2022-03-06 13:29:38 +00:00
Stream kfStream = kvp.Value.GetDataForkStream();
byte[] trackContents = new byte[kfStream.Length];
2022-03-06 13:29:38 +00:00
kfStream.Position = 0;
kfStream.EnsureRead(trackContents, 0, trackContents.Length);
2022-03-06 13:29:38 +00:00
kfBlockTrackType.Size = (ulong)trackContents.Length;
kfBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
kfBlockTrackTypes.Add(kfBlockTrackType);
}
2022-03-06 13:29:38 +00:00
sidecar.BlockMedia[0].Track = kfBlockTrackTypes.OrderBy(t => t.Cylinder).
ThenBy(t => t.Head).ToArray();
}
else
2020-02-27 23:48:41 +00:00
AaruConsole.
ErrorWriteLine(Localization.Core.KryoFlux_image_do_not_same_number_tracks_0_disk_image_1_ignoring,
2022-03-06 13:29:38 +00:00
kfImage.Info.Cylinders, image.Info.Cylinders);
else
AaruConsole.
ErrorWriteLine(Localization.Core.KryoFlux_image_do_not_same_number_heads_0_disk_image_1_ignoring,
2022-03-06 13:29:38 +00:00
kfImage.Info.Heads, image.Info.Heads);
}
2022-03-06 13:29:38 +00:00
}
#endregion
2022-03-06 13:29:38 +00:00
#region DiscFerret
string dfiFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
Path.GetFileNameWithoutExtension(imagePath) + ".dfi");
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
if(!File.Exists(dfiFilePath))
return;
2022-03-06 13:29:38 +00:00
var dfiImage = new DiscFerret();
var dfiFilter = new ZZZNoFilter();
dfiFilter.Open(dfiFilePath);
2022-03-06 13:29:38 +00:00
if(!dfiImage.Identify(dfiFilter))
return;
2022-03-06 13:29:38 +00:00
try
{
dfiImage.Open(dfiFilter);
}
catch(NotImplementedException) {}
UpdateStatus(Localization.Core.Hashing_DiscFerret_image);
2022-03-06 13:29:38 +00:00
if(image.Info.Heads == dfiImage.Info.Heads)
if(dfiImage.Info.Cylinders >= image.Info.Cylinders)
{
List<BlockTrackType> dfiBlockTrackTypes = new();
ulong currentSector = 0;
Stream dfiStream = dfiFilter.GetDataForkStream();
foreach(int t in dfiImage.TrackOffsets.Keys)
{
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
var dfiBlockTrackType = new BlockTrackType
{
2022-03-06 13:29:38 +00:00
Cylinder = (uint)(t / image.Info.Heads),
Head = (ushort)(t % image.Info.Heads),
Image = new ImageType
{
2022-03-06 13:29:38 +00:00
format = dfiImage.Format,
Value = Path.GetFileName(dfiFilePath)
}
2022-03-06 13:29:38 +00:00
};
2022-03-06 13:29:38 +00:00
if(dfiBlockTrackType.Cylinder < image.Info.Cylinders)
{
dfiBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
dfiBlockTrackType.EndSector = currentSector - 1;
dfiBlockTrackType.Sectors = image.Info.SectorsPerTrack;
dfiBlockTrackType.BytesPerSector = image.Info.SectorSize;
dfiBlockTrackType.Format = trkFormat;
}
2022-03-06 13:29:38 +00:00
if(dfiImage.TrackOffsets.TryGetValue(t, out long offset) &&
dfiImage.TrackLengths.TryGetValue(t, out long length))
{
dfiBlockTrackType.Image.offset = (ulong)offset;
byte[] trackContents = new byte[length];
2022-03-06 13:29:38 +00:00
dfiStream.Position = offset;
dfiStream.EnsureRead(trackContents, 0, trackContents.Length);
2022-03-06 13:29:38 +00:00
dfiBlockTrackType.Size = (ulong)trackContents.Length;
dfiBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
}
2022-03-06 13:29:38 +00:00
dfiBlockTrackTypes.Add(dfiBlockTrackType);
}
2022-03-06 13:29:38 +00:00
2022-03-07 07:36:44 +00:00
sidecar.BlockMedia[0].Track = dfiBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
2022-03-06 13:29:38 +00:00
}
else
2020-02-27 23:48:41 +00:00
AaruConsole.
ErrorWriteLine(Localization.Core.DiscFerret_image_do_not_same_number_tracks_0_disk_image_1_ignoring,
2022-03-06 13:29:38 +00:00
dfiImage.Info.Cylinders, image.Info.Cylinders);
else
AaruConsole.
ErrorWriteLine(Localization.Core.DiscFerret_image_do_not_same_number_heads_0_disk_image_1_ignoring,
2022-03-06 13:29:38 +00:00
dfiImage.Info.Heads, image.Info.Heads);
#endregion
// TODO: Implement support for getting CHS from SCSI mode pages
2017-08-08 13:40:32 +01:00
}
2017-12-19 20:33:03 +00:00
}