mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2025-12-16 19:24:40 +00:00
Implement sector verification in tool.
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
231
tool/ecc_cd.c
Normal 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;
|
||||||
|
}
|
||||||
31
tool/main.c
31
tool/main.c
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user