adding --enable-taler-wallet configure option to build a reduced version of libgnunet...
[oweals/gnunet.git] / src / util / crypto_hash_file.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001-2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19
20 */
21
22 /**
23  * @file util/crypto_hash_file.c
24  * @brief incremental hashing of files
25  * @author Christian Grothoff
26  */
27
28
29 /**
30  * Context used when hashing a file.
31  */
32 struct GNUNET_CRYPTO_FileHashContext
33 {
34
35   /**
36    * Function to call upon completion.
37    */
38   GNUNET_CRYPTO_HashCompletedCallback callback;
39
40   /**
41    * Closure for callback.
42    */
43   void *callback_cls;
44
45   /**
46    * IO buffer.
47    */
48   unsigned char *buffer;
49
50   /**
51    * Name of the file we are hashing.
52    */
53   char *filename;
54
55   /**
56    * File descriptor.
57    */
58   struct GNUNET_DISK_FileHandle *fh;
59
60   /**
61    * Cummulated hash.
62    */
63   gcry_md_hd_t md;
64
65   /**
66    * Size of the file.
67    */
68   uint64_t fsize;
69
70   /**
71    * Current offset.
72    */
73   uint64_t offset;
74
75   /**
76    * Current task for hashing.
77    */
78   struct GNUNET_SCHEDULER_Task * task;
79
80   /**
81    * Priority we use.
82    */
83   enum GNUNET_SCHEDULER_Priority priority;
84
85   /**
86    * Blocksize.
87    */
88   size_t bsize;
89
90 };
91
92
93 /**
94  * Report result of hash computation to callback
95  * and free associated resources.
96  */
97 static void
98 file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc,
99                   const struct GNUNET_HashCode * res)
100 {
101   fhc->callback (fhc->callback_cls, res);
102   GNUNET_free (fhc->filename);
103   if (!GNUNET_DISK_handle_invalid (fhc->fh))
104     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
105   gcry_md_close (fhc->md);
106   GNUNET_free (fhc);            /* also frees fhc->buffer */
107 }
108
109
110 /**
111  * File hashing task.
112  *
113  * @param cls closure
114  * @param tc context
115  */
116 static void
117 file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
118 {
119   struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
120   struct GNUNET_HashCode *res;
121   size_t delta;
122
123   fhc->task = NULL;
124   GNUNET_assert (fhc->offset <= fhc->fsize);
125   delta = fhc->bsize;
126   if (fhc->fsize - fhc->offset < delta)
127     delta = fhc->fsize - fhc->offset;
128   if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta))
129   {
130     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename);
131     file_hash_finish (fhc, NULL);
132     return;
133   }
134   gcry_md_write (fhc->md, fhc->buffer, delta);
135   fhc->offset += delta;
136   if (fhc->offset == fhc->fsize)
137   {
138     res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512);
139     file_hash_finish (fhc, res);
140     return;
141   }
142   fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
143                                                   &file_hash_task, fhc);
144 }
145
146
147 /**
148  * Compute the hash of an entire file.
149  *
150  * @param priority scheduling priority to use
151  * @param filename name of file to hash
152  * @param blocksize number of bytes to process in one task
153  * @param callback function to call upon completion
154  * @param callback_cls closure for callback
155  * @return NULL on (immediate) errror
156  */
157 struct GNUNET_CRYPTO_FileHashContext *
158 GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority,
159                          const char *filename, size_t blocksize,
160                          GNUNET_CRYPTO_HashCompletedCallback callback,
161                          void *callback_cls)
162 {
163   struct GNUNET_CRYPTO_FileHashContext *fhc;
164
165   GNUNET_assert (blocksize > 0);
166   fhc =
167       GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
168   fhc->callback = callback;
169   fhc->callback_cls = callback_cls;
170   fhc->buffer = (unsigned char *) &fhc[1];
171   fhc->filename = GNUNET_strdup (filename);
172   if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0))
173   {
174     GNUNET_break (0);
175     GNUNET_free (fhc);
176     return NULL;
177   }
178   fhc->bsize = blocksize;
179   if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES))
180   {
181     GNUNET_free (fhc->filename);
182     GNUNET_free (fhc);
183     return NULL;
184   }
185   fhc->fh =
186       GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
187                              GNUNET_DISK_PERM_NONE);
188   if (!fhc->fh)
189   {
190     GNUNET_free (fhc->filename);
191     GNUNET_free (fhc);
192     return NULL;
193   }
194   fhc->priority = priority;
195   fhc->task =
196       GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc);
197   return fhc;
198 }
199
200
201 /**
202  * Cancel a file hashing operation.
203  *
204  * @param fhc operation to cancel (callback must not yet have been invoked)
205  */
206 void
207 GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
208 {
209   GNUNET_SCHEDULER_cancel (fhc->task);
210   GNUNET_free (fhc->filename);
211   GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
212   GNUNET_free (fhc);
213 }
214
215 /* end of crypto_hash_file.c */