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
42 * Function to call upon completion.
44 GNUNET_CRYPTO_HashCompletedCallback callback;
47 * Closure for callback.
54 unsigned char *buffer;
57 * Name of the file we are hashing.
64 struct GNUNET_DISK_FileHandle *fh;
82 * Current task for hashing.
84 struct GNUNET_SCHEDULER_Task * task;
89 enum GNUNET_SCHEDULER_Priority priority;
100 * Report result of hash computation to callback
101 * and free associated resources.
104 file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
105 const struct GNUNET_HashCode * res)
107 fhc->callback (fhc->callback_cls, res);
108 GNUNET_free (fhc->filename);
109 if (!GNUNET_DISK_handle_invalid (fhc->fh))
110 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
111 gcry_md_close (fhc->md);
112 GNUNET_free (fhc); /* also frees fhc->buffer */
122 file_hash_task (void *cls)
124 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
125 struct GNUNET_HashCode *res;
130 GNUNET_assert (fhc->offset <= fhc->fsize);
132 if (fhc->fsize - fhc->offset < delta)
133 delta = fhc->fsize - fhc->offset;
134 sret = GNUNET_DISK_file_read (fhc->fh,
138 (delta != (size_t) sret) )
140 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
143 file_hash_finish (fhc,
147 gcry_md_write (fhc->md,
150 fhc->offset += delta;
151 if (fhc->offset == fhc->fsize)
153 res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md,
155 file_hash_finish (fhc, res);
158 fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
165 * Compute the hash of an entire file.
167 * @param priority scheduling priority to use
168 * @param filename name of file to hash
169 * @param blocksize number of bytes to process in one task
170 * @param callback function to call upon completion
171 * @param callback_cls closure for @a callback
172 * @return NULL on (immediate) errror
174 struct GNUNET_CRYPTO_FileHashContext *
175 GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
176 const char *filename,
178 GNUNET_CRYPTO_HashCompletedCallback callback,
181 struct GNUNET_CRYPTO_FileHashContext *fhc;
183 GNUNET_assert (blocksize > 0);
185 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
186 fhc->callback = callback;
187 fhc->callback_cls = callback_cls;
188 fhc->buffer = (unsigned char *) &fhc[1];
189 fhc->filename = GNUNET_strdup (filename);
190 if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
196 fhc->bsize = blocksize;
198 GNUNET_DISK_file_size (filename,
203 GNUNET_free (fhc->filename);
207 fhc->fh = GNUNET_DISK_file_open (filename,
208 GNUNET_DISK_OPEN_READ,
209 GNUNET_DISK_PERM_NONE);
212 GNUNET_free (fhc->filename);
216 fhc->priority = priority;
217 fhc->task = GNUNET_SCHEDULER_add_with_priority (priority,
225 * Cancel a file hashing operation.
227 * @param fhc operation to cancel (callback must not yet have been invoked)
230 GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
232 GNUNET_SCHEDULER_cancel (fhc->task);
233 GNUNET_free (fhc->filename);
234 GNUNET_break (GNUNET_OK ==
235 GNUNET_DISK_file_close (fhc->fh));
239 /* end of crypto_hash_file.c */