2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/crypto_hash_file.c
23 * @brief incremental hashing of files
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
30 #define LOG(kind, ...) GNUNET_log_from(kind, "util-crypto-hash-file", __VA_ARGS__)
32 #define LOG_STRERROR_FILE(kind, syscall, filename) GNUNET_log_from_strerror_file(kind, "util-crypto-hash-file", syscall, filename)
36 * Context used when hashing a file.
38 struct GNUNET_CRYPTO_FileHashContext {
40 * Function to call upon completion.
42 GNUNET_CRYPTO_HashCompletedCallback callback;
45 * Closure for callback.
52 unsigned char *buffer;
55 * Name of the file we are hashing.
62 struct GNUNET_DISK_FileHandle *fh;
80 * Current task for hashing.
82 struct GNUNET_SCHEDULER_Task * task;
87 enum GNUNET_SCHEDULER_Priority priority;
97 * Report result of hash computation to callback
98 * and free associated resources.
101 file_hash_finish(struct GNUNET_CRYPTO_FileHashContext *fhc,
102 const struct GNUNET_HashCode * res)
104 fhc->callback(fhc->callback_cls, res);
105 GNUNET_free(fhc->filename);
106 if (!GNUNET_DISK_handle_invalid(fhc->fh))
107 GNUNET_break(GNUNET_OK == GNUNET_DISK_file_close(fhc->fh));
108 gcry_md_close(fhc->md);
109 GNUNET_free(fhc); /* also frees fhc->buffer */
119 file_hash_task(void *cls)
121 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
122 struct GNUNET_HashCode *res;
127 GNUNET_assert(fhc->offset <= fhc->fsize);
129 if (fhc->fsize - fhc->offset < delta)
130 delta = fhc->fsize - fhc->offset;
131 sret = GNUNET_DISK_file_read(fhc->fh,
135 (delta != (size_t)sret))
137 LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_WARNING,
140 file_hash_finish(fhc,
144 gcry_md_write(fhc->md,
147 fhc->offset += delta;
148 if (fhc->offset == fhc->fsize)
150 res = (struct GNUNET_HashCode *)gcry_md_read(fhc->md,
152 file_hash_finish(fhc, res);
155 fhc->task = GNUNET_SCHEDULER_add_with_priority(fhc->priority,
162 * Compute the hash of an entire file.
164 * @param priority scheduling priority to use
165 * @param filename name of file to hash
166 * @param blocksize number of bytes to process in one task
167 * @param callback function to call upon completion
168 * @param callback_cls closure for @a callback
169 * @return NULL on (immediate) errror
171 struct GNUNET_CRYPTO_FileHashContext *
172 GNUNET_CRYPTO_hash_file(enum GNUNET_SCHEDULER_Priority priority,
173 const char *filename,
175 GNUNET_CRYPTO_HashCompletedCallback callback,
178 struct GNUNET_CRYPTO_FileHashContext *fhc;
180 GNUNET_assert(blocksize > 0);
182 GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_FileHashContext) + blocksize);
183 fhc->callback = callback;
184 fhc->callback_cls = callback_cls;
185 fhc->buffer = (unsigned char *)&fhc[1];
186 fhc->filename = GNUNET_strdup(filename);
187 if (GPG_ERR_NO_ERROR != gcry_md_open(&fhc->md, GCRY_MD_SHA512, 0))
193 fhc->bsize = blocksize;
195 GNUNET_DISK_file_size(filename,
200 GNUNET_free(fhc->filename);
204 fhc->fh = GNUNET_DISK_file_open(filename,
205 GNUNET_DISK_OPEN_READ,
206 GNUNET_DISK_PERM_NONE);
209 GNUNET_free(fhc->filename);
213 fhc->priority = priority;
214 fhc->task = GNUNET_SCHEDULER_add_with_priority(priority,
222 * Cancel a file hashing operation.
224 * @param fhc operation to cancel (callback must not yet have been invoked)
227 GNUNET_CRYPTO_hash_file_cancel(struct GNUNET_CRYPTO_FileHashContext *fhc)
229 GNUNET_SCHEDULER_cancel(fhc->task);
230 GNUNET_free(fhc->filename);
231 GNUNET_break(GNUNET_OK ==
232 GNUNET_DISK_file_close(fhc->fh));
236 /* end of crypto_hash_file.c */