Implement sector verification in tool.

This commit is contained in:
2022-10-12 19:08:46 +01:00
parent 0f07e85746
commit 0694b32a9b
5 changed files with 359 additions and 2 deletions

View File

@@ -4,5 +4,5 @@ find_package(ICU COMPONENTS uc REQUIRED)
include_directories(${ICU_INCLUDE_DIRS}) include_directories(${ICU_INCLUDE_DIRS})
add_executable(aaruformattool main.c main.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c) add_executable(aaruformattool main.c main.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c ecc_cd.c)
target_link_libraries(aaruformattool "aaruformat" ICU::uc) target_link_libraries(aaruformattool "aaruformat" ICU::uc)

View File

@@ -21,6 +21,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <aaruformat.h>
int identify(char* path); int identify(char* path);
int info(char* path); int info(char* path);
char* byte_array_to_hex_string(const unsigned char* array, int array_size); char* byte_array_to_hex_string(const unsigned char* array, int array_size);
@@ -28,5 +30,15 @@ int read(unsigned long long sector_no, char* path);
int printhex(unsigned char* array, unsigned int length, int width, bool color); int printhex(unsigned char* array, unsigned int length, int width, bool color);
int read_long(unsigned long long sector_no, char* path); int read_long(unsigned long long sector_no, char* path);
int verify(char* path); int verify(char* path);
int verify_sectors(char* path);
bool check_cd_sector_channel(CdEccContext* context,
uint8_t* sector,
bool* unknown,
bool* has_edc,
bool* edc_correct,
bool* has_ecc_p,
bool* ecc_p_correct,
bool* has_ecc_q,
bool* ecc_q_correct);
#endif // LIBAARUFORMAT_TOOL_AARUFORMATTOOL_H_ #endif // LIBAARUFORMAT_TOOL_AARUFORMATTOOL_H_

231
tool/ecc_cd.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2022 Natalia Portillo.
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdbool.h>
#include <stdint.h>
#include <aaruformat.h>
bool check_cd_sector_channel(CdEccContext* context,
uint8_t* sector,
bool* unknown,
bool* has_edc,
bool* edc_correct,
bool* has_ecc_p,
bool* ecc_p_correct,
bool* has_ecc_q,
bool* ecc_q_correct)
{
int i;
uint32_t storedEdc, edc, calculatedEdc;
int size, pos;
uint8_t zeroaddress[4];
*has_edc = false;
*has_ecc_p = false;
*has_ecc_q = false;
*edc_correct = false;
*ecc_p_correct = false;
*ecc_q_correct = false;
*unknown = false;
if(sector[0x000] != 0x00 || sector[0x001] != 0xFF || sector[0x002] != 0xFF || sector[0x003] != 0xFF ||
sector[0x004] != 0xFF || sector[0x005] != 0xFF || sector[0x006] != 0xFF || sector[0x007] != 0xFF ||
sector[0x008] != 0xFF || sector[0x009] != 0xFF || sector[0x00A] != 0xFF || sector[0x00B] != 0x00)
{
*unknown = true;
return false;
}
if((sector[0x00F] & 0x03) == 0x00) // Mode 0
{
for(i = 0x010; i < 0x930; i++)
if(sector[i] != 0x00)
{
fprintf(stderr,
"Mode 0 sector with error at address: %2X:%2X:%2X.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
return false;
}
return true;
}
if((sector[0x00F] & 0x03) == 0x01) // Mode 1
{
if(sector[0x814] != 0x00 ||
// reserved (8 bytes)
sector[0x815] != 0x00 || sector[0x816] != 0x00 || sector[0x817] != 0x00 || sector[0x818] != 0x00 ||
sector[0x819] != 0x00 || sector[0x81A] != 0x00 || sector[0x81B] != 0x00)
{
fprintf(stderr,
"Mode 1 with data in reserved bytes at address: %2X:%2X:%2X.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
return false;
}
*has_edc = true;
*has_ecc_p = true;
*has_ecc_q = true;
*ecc_p_correct = aaruf_ecc_cd_check(context, sector, sector, 86, 24, 2, 86, sector, 0xC, 0x10, 0x81C);
*ecc_q_correct = aaruf_ecc_cd_check(context, sector, sector, 52, 43, 86, 88, sector, 0xC, 0x10, 0x81C + 0xAC);
storedEdc =
(sector[0x813] << 24) + (sector[0x812] << 16) + (sector[0x811] << 8) + sector[0x810]; // TODO: Check casting
edc = 0;
size = 0x810;
pos = 0;
for(; size > 0; size--) edc = (edc >> 8) ^ context->edcTable[(edc ^ sector[pos++]) & 0xFF];
calculatedEdc = edc;
*edc_correct = calculatedEdc == storedEdc;
if(!*edc_correct)
{
fprintf(stderr,
"Mode 1 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n",
sector[0x00C],
sector[0x00D],
sector[0x00E],
calculatedEdc,
storedEdc);
}
if(!*ecc_p_correct)
{
fprintf(stderr,
"Mode 1 sector at address: %2X:%2X:%2X, fails ECC P check.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
}
if(!*ecc_q_correct)
{
fprintf(stderr,
"Mode 1 sector at address: %2X:%2X:%2X, fails ECC Q check.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
}
return *edc_correct && *ecc_p_correct && *ecc_q_correct;
}
if((sector[0x00F] & 0x03) == 0x02) // Mode 2
{
if((sector[0x012] & 0x20) == 0x20) // mode 2 form 2
{
if(sector[0x010] != sector[0x014] || sector[0x011] != sector[0x015] || sector[0x012] != sector[0x016] ||
sector[0x013] != sector[0x017])
fprintf(stderr,
"Subheader copies differ in mode 2 form 2 sector at address: %2X:%2X:%2X",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
storedEdc = sector[0x91C];
if(storedEdc == 0) return true;
*has_edc = true;
storedEdc = (sector[0x81B] << 24) + (sector[0x81A] << 16) + (sector[0x819] << 8) + sector[0x818];
edc = 0;
size = 0x808;
pos = 0x10;
for(; size > 0; size--) edc = (edc >> 8) ^ context->edcTable[(edc ^ sector[pos++]) & 0xFF];
calculatedEdc = edc;
*edc_correct = calculatedEdc == storedEdc;
if(!*edc_correct)
{
fprintf(stderr,
"Mode 2 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n",
sector[0x00C],
sector[0x00D],
sector[0x00E],
calculatedEdc,
storedEdc);
}
return *edc_correct;
}
*ecc_p_correct = aaruf_ecc_cd_check(context, zeroaddress, sector, 86, 24, 2, 86, sector, 0, 0x10, 0x81C);
*ecc_q_correct =
aaruf_ecc_cd_check(context, zeroaddress, sector, 52, 43, 86, 88, sector, 0, 0x10, 0x81C + 0xAC);
storedEdc = sector[0x818]; // TODO: Check cast
edc = 0;
size = 0x808;
pos = 0x10;
for(; size > 0; size--) edc = (edc >> 8) ^ context->edcTable[(edc ^ sector[pos++]) & 0xFF];
calculatedEdc = edc;
*edc_correct = calculatedEdc == storedEdc;
if(!*edc_correct)
{
fprintf(stderr,
"Mode 2 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n",
sector[0x00C],
sector[0x00D],
sector[0x00E],
calculatedEdc,
storedEdc);
}
if(!*ecc_p_correct)
{
fprintf(stderr,
"Mode 2 sector at address: %2X:%2X:%2X, fails ECC P check.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
}
if(!*ecc_q_correct)
{
fprintf(stderr,
"Mode 2 sector at address: %2X:%2X:%2X, fails ECC Q check.\n",
sector[0x00C],
sector[0x00D],
sector[0x00E]);
}
return *edc_correct && *ecc_p_correct && *ecc_q_correct;
}
fprintf(stderr,
"Unknown mode %d sector at address: %2X:%2X:%2X",
sector[0x00F],
sector[0x00C],
sector[0x00D],
sector[0x00E]);
return false;
}

View File

@@ -38,6 +38,7 @@ void usage()
printf("\tread\tReads a sector and prints it out on screen.\n"); printf("\tread\tReads a sector and prints it out on screen.\n");
printf("\tread_long\tReads a sector with all its prefixes and suffixes and prints it out on screen.\n"); printf("\tread_long\tReads a sector with all its prefixes and suffixes and prints it out on screen.\n");
printf("\tverify\tVerifies the integrity of all blocks in a AaruFormat image.\n"); printf("\tverify\tVerifies the integrity of all blocks in a AaruFormat image.\n");
printf("\tverify_sectors\tVerifies the integrity of all sectors in a AaruFormat image.\n");
printf("\n"); printf("\n");
printf("For help on the verb invoke the tool with the verb and no arguments.\n"); printf("For help on the verb invoke the tool with the verb and no arguments.\n");
} }
@@ -99,6 +100,17 @@ void usage_verify()
printf("\t<filename>\tPath to AaruFormat image to verify.\n"); printf("\t<filename>\tPath to AaruFormat image to verify.\n");
} }
void usage_verify_sectors()
{
printf("\n");
printf("Usage:\n");
printf("aaruformattool verify_sectors <filename>\n");
printf("Verifies the integrity of all sectors in a AaruFormat image.\n");
printf("\n");
printf("Arguments:\n");
printf("\t<filename>\tPath to AaruFormat image to verify.\n");
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
uint64_t sector_no = 0; uint64_t sector_no = 0;
@@ -207,7 +219,24 @@ int main(int argc, char* argv[])
return read(sector_no, argv[3]); return read(sector_no, argv[3]);
} }
if(strncmp(argv[1], "verify", strlen("verify")) == 0) if(strncmp(argv[1], "verify_sectors", strlen("verify_sectors")) == 0)
{
if(argc == 2)
{
usage_verify_sectors();
return -1;
}
if(argc > 3)
{
fprintf(stderr, "Invalid number of arguments\n");
usage_verify_sectors();
return -1;
}
return verify_sectors(argv[2]);
}
else if(strncmp(argv[1], "verify", strlen("verify")) == 0)
{ {
if(argc == 2) if(argc == 2)
{ {

View File

@@ -21,6 +21,8 @@
#include <aaruformat.h> #include <aaruformat.h>
#include "aaruformattool.h"
int verify(char* path) int verify(char* path)
{ {
aaruformatContext* ctx; aaruformatContext* ctx;
@@ -44,3 +46,86 @@ int verify(char* path)
return res; return res;
} }
int verify_sectors(char* path)
{
aaruformatContext* ctx;
uint64_t s;
uint8_t* buffer;
uint32_t buffer_len = 2352;
int32_t res;
CdEccContext* cd_ecc_context;
ctx = aaruf_open(path);
bool verify_result;
bool unknown, has_edc, edc_correct, has_ecc_p, ecc_p_correct, has_ecc_q, ecc_q_correct;
uint64_t errors, unknowns;
bool any_error;
if(ctx == NULL)
{
printf("Error %d when opening AaruFormat image.\n", errno);
return errno;
}
if(ctx->imageInfo.XmlMediaType != OpticalDisc)
{
printf("Image sectors do not contain checksums, cannot verify.\n");
return 0;
}
cd_ecc_context = aaruf_ecc_cd_init();
errors = 0;
unknown = 0;
any_error = false;
for(s = 0; s < ctx->imageInfo.Sectors; s++)
{
printf("\rVerifying sector %lu...", s);
res = aaruf_read_sector_long(ctx, s, buffer, &buffer_len);
if(res != AARUF_STATUS_OK)
{
fprintf(stderr, "\rError %d reading sector %lu\n.", res, s);
continue;
}
verify_result = check_cd_sector_channel(cd_ecc_context,
buffer,
&unknown,
&has_edc,
&edc_correct,
&has_ecc_p,
&ecc_p_correct,
&has_ecc_q,
&ecc_q_correct);
if(verify_result) continue;
if(unknown)
{
unknowns++;
printf("\rSector %lu cannot be verified.\n", s);
continue;
}
if(has_edc && !edc_correct) printf("\rSector %lu has an incorrect EDC value.\n", s);
if(has_ecc_p && !ecc_p_correct) printf("\rSector %lu has an incorrect EDC value.\n", s);
if(has_ecc_q && !ecc_q_correct) printf("\rSector %lu has an incorrect EDC value.\n", s);
errors++;
any_error = true;
}
if(any_error) printf("\rSome sectors had incorrect checksums.\n");
else
printf("\rAll sector checksums are correct.\n");
printf("Total sectors........... %lu\n", ctx->imageInfo.Sectors);
printf("Total errors............ %lu\n", errors);
printf("Total unknowns.......... %lu\n", unknowns);
printf("Total errors+unknowns... %lu\n", errors + unknowns);
return AARUF_STATUS_OK;
}