libaaruformat 1.0 Aaru Data Preservation Suite - Format Library

Loading...
Searching...
No Matches
checksum.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2025 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <inttypes.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "aaruformat/context.h"
26#include "aaruformat/enums.h"
27#include "aaruformat/structs/checksum.h"
28#include "aaruformat/structs/index.h"
29#include "log.h"
30
39 void process_checksum_block(aaruformat_context *ctx, const IndexEntry *entry)
40{
41 TRACE("Entering process_checksum_block(%p, %p)", ctx, entry);
42
43 int seek_result = 0;
44 size_t read_bytes = 0;
45 ChecksumHeader checksum_header;
46 ChecksumEntry const *checksum_entry = NULL;
47 uint8_t *data = NULL;
48 int j = 0;
49 size_t payload_pos = 0;
50
51 // Check if the context and image stream are valid
52 if(ctx == NULL || ctx->imageStream == NULL)
53 {
54 FATAL("Invalid context or image stream.");
55 return;
56 }
57
58 // Seek to block
59 seek_result = fseek(ctx->imageStream, entry->offset, SEEK_SET);
60 if(seek_result < 0 || ftell(ctx->imageStream) != entry->offset)
61 {
62 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
63
64 return;
65 }
66
67 // Even if those two checks shall have been done before
68 TRACE("Reading checksum block header at position %" PRIu64, entry->offset);
69 read_bytes = fread(&checksum_header, 1, sizeof(ChecksumHeader), ctx->imageStream);
70
71 if(read_bytes != sizeof(ChecksumHeader))
72 {
73 memset(&checksum_header, 0, sizeof(ChecksumHeader));
74 FATAL("Could not read checksums block header, continuing...\n");
75 return;
76 }
77
78 if(checksum_header.identifier != ChecksumBlock)
79 {
80 memset(&checksum_header, 0, sizeof(ChecksumHeader));
81 FATAL("Incorrect identifier for checksum block at position %" PRIu64 "\n", entry->offset);
82 return;
83 }
84
85 TRACE("Allocating %u bytes for checksum block", checksum_header.length);
86 data = (uint8_t *)malloc(checksum_header.length);
87
88 if(data == NULL)
89 {
90 memset(&checksum_header, 0, sizeof(ChecksumHeader));
91 FATAL("Could not allocate memory for checksum block, continuing...\n");
92 return;
93 }
94
95 TRACE("Reading checksum block data at position %" PRIu64, entry->offset + sizeof(ChecksumHeader));
96 read_bytes = fread(data, 1, checksum_header.length, ctx->imageStream);
97
98 if(read_bytes != checksum_header.length)
99 {
100 memset(&checksum_header, 0, sizeof(ChecksumHeader));
101 free(data);
102 FATAL("Could not read checksums block, continuing...\n");
103 return;
104 }
105
106 payload_pos = 0;
107 TRACE("Processing %u checksum entries", checksum_header.entries);
108 for(j = 0; j < checksum_header.entries; j++)
109 {
110 if(payload_pos + sizeof(ChecksumEntry) > checksum_header.length)
111 {
112 FATAL("Checksum entry %d exceeds block payload size", j);
113 break;
114 }
115
116 checksum_entry = (const ChecksumEntry *)&data[payload_pos];
117 payload_pos += sizeof(ChecksumEntry);
118
119 if(payload_pos + checksum_entry->length > checksum_header.length)
120 {
121 FATAL("Checksum payload for entry %d exceeds block payload size", j);
122 break;
123 }
124
125 switch(checksum_entry->type)
126 {
127 case Md5:
128 if(checksum_entry->length != MD5_DIGEST_LENGTH)
129 {
130 FATAL("MD5 checksum entry has invalid length %u", checksum_entry->length);
131 break;
132 }
133
134 TRACE("Found MD5 checksum");
135 memcpy(ctx->checksums.md5, &data[payload_pos], MD5_DIGEST_LENGTH);
136 ctx->checksums.hasMd5 = true;
137 break;
138 case Sha1:
139 if(checksum_entry->length != SHA1_DIGEST_LENGTH)
140 {
141 FATAL("SHA1 checksum entry has invalid length %u", checksum_entry->length);
142 break;
143 }
144
145 TRACE("Found SHA1 checksum");
146 memcpy(ctx->checksums.sha1, &data[payload_pos], SHA1_DIGEST_LENGTH);
147 ctx->checksums.hasSha1 = true;
148 break;
149 case Sha256:
150 if(checksum_entry->length != SHA256_DIGEST_LENGTH)
151 {
152 FATAL("SHA256 checksum entry has invalid length %u", checksum_entry->length);
153 break;
154 }
155
156 TRACE("Found SHA256 checksum");
157 memcpy(ctx->checksums.sha256, &data[payload_pos], SHA256_DIGEST_LENGTH);
158 ctx->checksums.hasSha256 = true;
159 break;
160 case SpamSum:
161 TRACE("Found SpamSum checksum of size %u", checksum_entry->length);
162 free(ctx->checksums.spamsum);
163 ctx->checksums.spamsum = NULL;
164
165 ctx->checksums.spamsum = malloc(checksum_entry->length + 1);
166
167 if(ctx->checksums.spamsum == NULL)
168 {
169 FATAL("Could not allocate memory for SpamSum digest");
170 break;
171 }
172
173 memcpy(ctx->checksums.spamsum, &data[payload_pos], checksum_entry->length);
174 ctx->checksums.spamsum[checksum_entry->length] = '\0';
175 ctx->checksums.hasSpamSum = true;
176 break;
177 default:
178 TRACE("Unknown checksum type %u, skipping", checksum_entry->type);
179 break;
180 }
181
182 payload_pos += checksum_entry->length;
183 }
184
185 checksum_entry = NULL;
186 free(data);
187
188 TRACE("Exiting process_checksum_block()");
189}
process_checksum_block
void process_checksum_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a checksum block from the image stream.
Definition checksum.c:39
checksum.h
On-disk layout definitions for the checksum block (BlockType::ChecksumBlock).
context.h
Central runtime context structures for libaaruformat (image state, caches, checksum buffers).
MD5_DIGEST_LENGTH
#define MD5_DIGEST_LENGTH
Definition context.h:69
enums.h
ChecksumBlock
@ ChecksumBlock
Block containing contents checksums.
Definition enums.h:152
Sha1
@ Sha1
SHA-1 hash.
Definition enums.h:170
Md5
@ Md5
MD5 hash.
Definition enums.h:169
Sha256
@ Sha256
SHA-256 hash.
Definition enums.h:171
SpamSum
@ SpamSum
SpamSum (context-triggered piecewise hash).
Definition enums.h:172
index.h
On‑disk index block header and entry structures (versions 1, 2 and 3).
log.h
FATAL
#define FATAL(fmt,...)
Definition log.h:40
TRACE
#define TRACE(fmt,...)
Definition log.h:25
SHA1_DIGEST_LENGTH
#define SHA1_DIGEST_LENGTH
Definition sha1.h:39
SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH
Definition sha256.h:38
ChecksumEntry
Per-checksum metadata immediately followed by the digest / signature bytes.
Definition checksum.h:91
ChecksumEntry::length
uint32_t length
Length in bytes of the digest that immediately follows this structure.
Definition checksum.h:93
ChecksumEntry::type
uint8_t type
Algorithm used (value from ChecksumAlgorithm).
Definition checksum.h:92
ChecksumHeader
Header that precedes the sequence of checksum entries for a checksum block.
Definition checksum.h:74
ChecksumHeader::identifier
uint32_t identifier
Block identifier, must be BlockType::ChecksumBlock.
Definition checksum.h:75
ChecksumHeader::length
uint32_t length
Length in bytes of the payload (all entries + their digest data, excluding this header).
Definition checksum.h:76
ChecksumHeader::entries
uint8_t entries
Number of checksum entries that follow in the payload.
Definition checksum.h:77
Checksums::spamsum
uint8_t * spamsum
SpamSum fuzzy hash (ASCII), allocated length+1 with trailing 0.
Definition context.h:110
Checksums::hasSha256
bool hasSha256
True if sha256[] buffer populated.
Definition context.h:103
Checksums::sha1
uint8_t sha1[20]
SHA-1 digest (20 bytes).
Definition context.h:107
Checksums::sha256
uint8_t sha256[32]
SHA-256 digest (32 bytes).
Definition context.h:108
Checksums::md5
uint8_t md5[16]
MD5 digest (16 bytes).
Definition context.h:106
Checksums::hasSpamSum
bool hasSpamSum
True if spamsum pointer allocated and signature read.
Definition context.h:105
Checksums::hasSha1
bool hasSha1
True if sha1[] buffer populated.
Definition context.h:102
Checksums::hasMd5
bool hasMd5
True if md5[] buffer populated.
Definition context.h:101
IndexEntry
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
IndexEntry::offset
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
aaruformat_context::checksums
Checksums checksums
Whole-image checksums discovered.
Definition context.h:269
aaruformat_context::imageStream
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176