23#include <apr_file_io.h>
31static apr_status_t checksum_big_file(
const char *filename, apr_off_t size,
ft_hash_t *hash_out, apr_pool_t *gc_pool);
32static apr_status_t big_filecmp(apr_pool_t *pool,
const char *fname1,
const char *fname2, apr_off_t size,
int *result_out);
43static apr_status_t checksum_small_file(
const char *filename, apr_off_t size,
ft_hash_t *hash_out, apr_pool_t *gc_pool)
46 apr_file_t *file_descriptor = NULL;
47 apr_mmap_t *memory_map = NULL;
48 memset(errbuf, 0,
sizeof(errbuf));
49 apr_status_t status = APR_SUCCESS;
51 status = apr_file_open(&file_descriptor, filename, APR_READ | APR_BINARY, APR_OS_DEFAULT, gc_pool);
52 if (APR_SUCCESS != status) {
56 status = apr_mmap_create(&memory_map, file_descriptor, 0, (apr_size_t) size, APR_MMAP_READ, gc_pool);
57 if (APR_SUCCESS != status) {
58 (void) apr_file_close(file_descriptor);
59 return checksum_big_file(filename, size, hash_out, gc_pool);
64 status = apr_mmap_delete(memory_map);
65 if (APR_SUCCESS != status) {
66 DEBUG_ERR(
"error calling apr_mmap_delete: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
67 (void) apr_file_close(file_descriptor);
70 status = apr_file_close(file_descriptor);
71 if (APR_SUCCESS != status) {
72 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
79static apr_status_t checksum_big_file(
const char *filename, apr_off_t size,
ft_hash_t *hash_out, apr_pool_t *gc_pool)
85 apr_file_t *file_descriptor = NULL;
86 memset(data_chunk, 0,
sizeof(data_chunk));
87 memset(errbuf, 0,
sizeof(errbuf));
88 apr_status_t status = APR_SUCCESS;
96 status = apr_file_open(&file_descriptor, filename, APR_READ | APR_BINARY, APR_OS_DEFAULT, gc_pool);
97 if (APR_SUCCESS != status) {
98 XXH3_freeState(state);
104 status = apr_file_read(file_descriptor, data_chunk, &rbytes);
105 if ((APR_SUCCESS == status || (APR_EOF == status && rbytes > 0))) {
107 DEBUG_ERR(
"Error during hash update for file: %s", filename);
108 XXH3_freeState(state);
109 (void) apr_file_close(file_descriptor);
113 }
while (APR_SUCCESS == status);
115 if (APR_EOF != status) {
116 DEBUG_ERR(
"unable to read(%s, O_RDONLY), skipping: %s", filename, apr_strerror(status, errbuf,
sizeof(errbuf)));
117 XXH3_freeState(state);
118 (void) apr_file_close(file_descriptor);
123 XXH3_freeState(state);
125 status = apr_file_close(file_descriptor);
126 if (APR_SUCCESS != status) {
127 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
137 if (size < excess_size) {
138 return checksum_small_file(filename, size, hash_out, gc_pool);
141 return checksum_big_file(filename, size, hash_out, gc_pool);
144static apr_status_t small_filecmp(apr_pool_t *pool,
const char *fname1,
const char *fname2, apr_off_t size,
int *result_out)
147 apr_file_t *fd1 = NULL;
148 apr_file_t *fd2 = NULL;
149 apr_mmap_t *mm1 = NULL;
150 apr_mmap_t *mm2 = NULL;
151 memset(errbuf, 0,
sizeof(errbuf));
152 apr_status_t status = APR_SUCCESS;
159 status = apr_file_open(&fd1, fname1, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool);
160 if (APR_SUCCESS != status) {
164 status = apr_mmap_create(&mm1, fd1, 0, (apr_size_t) size, APR_MMAP_READ, pool);
165 if (APR_SUCCESS != status) {
166 (void) apr_file_close(fd1);
167 return big_filecmp(pool, fname1, fname2, size, result_out);
170 status = apr_file_open(&fd2, fname2, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool);
171 if (APR_SUCCESS != status) {
172 apr_mmap_delete(mm1);
173 (void) apr_file_close(fd1);
177 status = apr_mmap_create(&mm2, fd2, 0, size, APR_MMAP_READ, pool);
178 if (APR_SUCCESS != status) {
179 (void) apr_file_close(fd2);
180 (void) apr_file_close(fd2);
181 (void) apr_file_close(fd1);
182 return big_filecmp(pool, fname1, fname2, size, result_out);
185 *result_out = memcmp(mm1->mm, mm2->mm, size);
187 status = apr_mmap_delete(mm2);
188 if (APR_SUCCESS != status) {
189 DEBUG_ERR(
"error calling apr_mmap_delete: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
190 (void) apr_file_close(fd2);
191 (void) apr_mmap_delete(mm1);
192 (void) apr_file_close(fd1);
195 status = apr_file_close(fd2);
196 if (APR_SUCCESS != status) {
197 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
198 (void) apr_mmap_delete(mm1);
199 (void) apr_file_close(fd1);
203 status = apr_mmap_delete(mm1);
204 if (APR_SUCCESS != status) {
205 DEBUG_ERR(
"error calling apr_mmap_delete: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
206 (void) apr_file_close(fd1);
209 status = apr_file_close(fd1);
210 if (APR_SUCCESS != status) {
211 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status, errbuf,
sizeof(errbuf)));
218static apr_status_t big_filecmp(apr_pool_t *pool,
const char *fname1,
const char *fname2, apr_off_t size,
int *result_out)
220 unsigned char data_chunk1[
HUGE_LEN];
221 unsigned char data_chunk2[
HUGE_LEN];
227 apr_file_t *fd1 = NULL;
228 apr_file_t *fd2 = NULL;
229 memset(data_chunk1, 0,
sizeof(data_chunk1));
230 memset(data_chunk2, 0,
sizeof(data_chunk2));
231 memset(errbuf, 0,
sizeof(errbuf));
232 apr_status_t status1 = APR_SUCCESS;
233 apr_status_t status2 = APR_SUCCESS;
240 status1 = apr_file_open(&fd1, fname1, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool);
241 if (APR_SUCCESS != status1) {
245 status1 = apr_file_open(&fd2, fname2, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool);
246 if (APR_SUCCESS != status1) {
247 (void) apr_file_close(fd1);
253 status1 = apr_file_read(fd1, data_chunk1, &rbytes1);
255 status2 = apr_file_read(fd2, data_chunk2, &rbytes2);
256 if ((APR_SUCCESS == status1) && (APR_SUCCESS == status2) && (rbytes2 == rbytes1)) {
257 *result_out = memcmp(data_chunk1, data_chunk2, rbytes1);
259 }
while ((APR_SUCCESS == status1) && (APR_SUCCESS == status2) && (0 == *result_out) && (rbytes2 == rbytes1));
261 if ((APR_EOF != status1) && (APR_EOF != status2) && (0 == *result_out)) {
262 DEBUG_ERR(
"1:unable to read %s (%" APR_SIZE_T_FMT
"): %s", fname1, rbytes1,
263 apr_strerror(status1, errbuf,
sizeof(errbuf)));
264 DEBUG_ERR(
"2:unable to read %s (%" APR_SIZE_T_FMT
"): %s", fname2, rbytes2,
265 apr_strerror(status2, errbuf,
sizeof(errbuf)));
269 status1 = apr_file_close(fd2);
270 if (APR_SUCCESS != status1) {
271 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status1, errbuf,
sizeof(errbuf)));
272 (void) apr_file_close(fd1);
276 status1 = apr_file_close(fd1);
277 if (APR_SUCCESS != status1) {
278 DEBUG_ERR(
"error calling apr_file_close: %s", apr_strerror(status1, errbuf,
sizeof(errbuf)));
285extern apr_status_t
filecmp(apr_pool_t *pool,
const char *fname1,
const char *fname2, apr_off_t size, apr_off_t excess_size,
288 if (size < excess_size) {
289 return small_filecmp(pool, fname1, fname2, size, result_out);
292 return big_filecmp(pool, fname1, fname2, size, result_out);
Defines the core checksum type used throughout the application.
UTIL debug output macros.
#define DEBUG_ERR(str, arg...)
Display error message at the level error.
static const size_t HUGE_LEN
The chunk size for processing large files.
apr_status_t checksum_file(const char *filename, apr_off_t size, apr_off_t excess_size, ft_hash_t *hash_out, apr_pool_t *gc_pool)
Calculates the XXH128 checksum of a file.
apr_status_t filecmp(apr_pool_t *pool, const char *fname1, const char *fname2, apr_off_t size, apr_off_t excess_size, int *result_out)
Compares two files byte-by-byte to determine if they are identical.
Interface for file comparison and checksum calculation.
static const size_t CHAR_MAX_VAL
The maximum value of a character, often used as a buffer size.
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t *statePtr)
Resets an XXH3_state_t to begin a new hash.
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest(XXH_NOESCAPE const XXH3_state_t *statePtr)
Returns the calculated XXH3 128-bit hash value from an XXH3_state_t.
struct XXH3_state_s XXH3_state_t
The state struct for the XXH3 streaming API.
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void *data, size_t len)
Unseeded 128-bit variant of XXH3.
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t *statePtr, XXH_NOESCAPE const void *input, size_t length)
Consumes a block of input to an XXH3_state_t.
The return value from 128-bit hashes.