aboutsummaryrefslogtreecommitdiff
path: root/src/lib/util/crypto_hash_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/crypto_hash_file.c')
-rw-r--r--src/lib/util/crypto_hash_file.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/src/lib/util/crypto_hash_file.c b/src/lib/util/crypto_hash_file.c
new file mode 100644
index 000000000..96d364d2b
--- /dev/null
+++ b/src/lib/util/crypto_hash_file.c
@@ -0,0 +1,236 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19
20 */
21/**
22 * @file util/crypto_hash_file.c
23 * @brief incremental hashing of files
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include <gcrypt.h>
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hash-file", \
32 __VA_ARGS__)
33
34#define LOG_STRERROR_FILE(kind, syscall, \
35 filename) GNUNET_log_from_strerror_file (kind, \
36 "util-crypto-hash-file", \
37 syscall, \
38 filename)
39
40
41/**
42 * Context used when hashing a file.
43 */
44struct GNUNET_CRYPTO_FileHashContext
45{
46 /**
47 * Function to call upon completion.
48 */
49 GNUNET_CRYPTO_HashCompletedCallback callback;
50
51 /**
52 * Closure for callback.
53 */
54 void *callback_cls;
55
56 /**
57 * IO buffer.
58 */
59 unsigned char *buffer;
60
61 /**
62 * Name of the file we are hashing.
63 */
64 char *filename;
65
66 /**
67 * File descriptor.
68 */
69 struct GNUNET_DISK_FileHandle *fh;
70
71 /**
72 * Cummulated hash.
73 */
74 gcry_md_hd_t md;
75
76 /**
77 * Size of the file.
78 */
79 uint64_t fsize;
80
81 /**
82 * Current offset.
83 */
84 uint64_t offset;
85
86 /**
87 * Current task for hashing.
88 */
89 struct GNUNET_SCHEDULER_Task *task;
90
91 /**
92 * Priority we use.
93 */
94 enum GNUNET_SCHEDULER_Priority priority;
95
96 /**
97 * Blocksize.
98 */
99 size_t bsize;
100};
101
102
103/**
104 * Report result of hash computation to callback
105 * and free associated resources.
106 */
107static void
108file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
109 const struct GNUNET_HashCode *res)
110{
111 fhc->callback (fhc->callback_cls, res);
112 GNUNET_free (fhc->filename);
113 if (! GNUNET_DISK_handle_invalid (fhc->fh))
114 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
115 gcry_md_close (fhc->md);
116 GNUNET_free (fhc); /* also frees fhc->buffer */
117}
118
119
120/**
121 * File hashing task.
122 *
123 * @param cls closure
124 */
125static void
126file_hash_task (void *cls)
127{
128 struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
129 struct GNUNET_HashCode *res;
130 size_t delta;
131 ssize_t sret;
132
133 fhc->task = NULL;
134 GNUNET_assert (fhc->offset <= fhc->fsize);
135 delta = fhc->bsize;
136 if (fhc->fsize - fhc->offset < delta)
137 delta = fhc->fsize - fhc->offset;
138 sret = GNUNET_DISK_file_read (fhc->fh,
139 fhc->buffer,
140 delta);
141 if ((sret < 0) ||
142 (delta != (size_t) sret))
143 {
144 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
145 "read",
146 fhc->filename);
147 file_hash_finish (fhc,
148 NULL);
149 return;
150 }
151 gcry_md_write (fhc->md,
152 fhc->buffer,
153 delta);
154 fhc->offset += delta;
155 if (fhc->offset == fhc->fsize)
156 {
157 res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md,
158 GCRY_MD_SHA512);
159 file_hash_finish (fhc, res);
160 return;
161 }
162 fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
163 &file_hash_task,
164 fhc);
165}
166
167
168struct GNUNET_CRYPTO_FileHashContext *
169GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
170 const char *filename,
171 size_t blocksize,
172 GNUNET_CRYPTO_HashCompletedCallback callback,
173 void *callback_cls)
174{
175 struct GNUNET_CRYPTO_FileHashContext *fhc;
176
177 GNUNET_assert (blocksize > 0);
178 fhc =
179 GNUNET_malloc (sizeof(struct GNUNET_CRYPTO_FileHashContext) + blocksize);
180 fhc->callback = callback;
181 fhc->callback_cls = callback_cls;
182 fhc->buffer = (unsigned char *) &fhc[1];
183 fhc->filename = GNUNET_strdup (filename);
184 if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
185 {
186 GNUNET_break (0);
187 GNUNET_free (fhc->filename);
188 GNUNET_free (fhc);
189 return NULL;
190 }
191 fhc->bsize = blocksize;
192 if (GNUNET_OK !=
193 GNUNET_DISK_file_size (filename,
194 &fhc->fsize,
195 GNUNET_NO,
196 GNUNET_YES))
197 {
198 GNUNET_free (fhc->filename);
199 GNUNET_free (fhc);
200 return NULL;
201 }
202 fhc->fh = GNUNET_DISK_file_open (filename,
203 GNUNET_DISK_OPEN_READ,
204 GNUNET_DISK_PERM_NONE);
205 if (! fhc->fh)
206 {
207 GNUNET_free (fhc->filename);
208 GNUNET_free (fhc);
209 return NULL;
210 }
211 fhc->priority = priority;
212 fhc->task = GNUNET_SCHEDULER_add_with_priority (priority,
213 &file_hash_task,
214 fhc);
215 return fhc;
216}
217
218
219/**
220 * Cancel a file hashing operation.
221 *
222 * @param fhc operation to cancel (callback must not yet have been invoked)
223 */
224void
225GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
226{
227 GNUNET_SCHEDULER_cancel (fhc->task);
228 GNUNET_free (fhc->filename);
229 GNUNET_break (GNUNET_OK ==
230 GNUNET_DISK_file_close (fhc->fh));
231 gcry_md_close (fhc->md);
232 GNUNET_free (fhc);
233}
234
235
236/* end of crypto_hash_file.c */