minor cleanup
[oweals/gnunet.git] / src / util / bio.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 2009 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 2, 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  * @file util/bio.c
22  * @brief functions for buffering IO
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_bio_lib.h"
27 #include "gnunet_disk_lib.h"
28
29 #define BIO_BUFFER_SIZE 65536
30
31 #define MAX_META_DATA (1024 * 1024)
32
33 /**
34  * Handle for buffered reading.
35  */
36 struct GNUNET_BIO_ReadHandle
37 {
38   struct GNUNET_DISK_FileHandle *fd;
39   char *emsg;
40   char *buffer;
41   size_t have;
42   size_t size;
43   off_t pos;
44 };
45
46
47 /**
48  * Open a file for reading.
49  *
50  * @param fn file name to be opened
51  * @return IO handle on success, NULL on error
52  */
53 struct GNUNET_BIO_ReadHandle *
54 GNUNET_BIO_read_open (const char *fn)
55 {
56   struct GNUNET_DISK_FileHandle *fd;
57   struct GNUNET_BIO_ReadHandle *h;
58
59   fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
60   if (NULL == fd)
61     return NULL;
62   h = GNUNET_malloc (sizeof (struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE);
63   h->buffer = (char *) &h[1];
64   h->size = BIO_BUFFER_SIZE;
65   h->fd = fd;
66   return h;
67 }
68
69
70 /**
71  * Close an open file.  Reports if any errors reading
72  * from the file were encountered.
73  *
74  * @param h file handle
75  * @param emsg set to the error message
76  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
77  */
78 int
79 GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg)
80 {
81   int err;
82
83   err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR;
84   if (emsg != NULL)
85     *emsg = h->emsg;
86   else
87     GNUNET_free_non_null (h->emsg);
88   GNUNET_DISK_file_close (h->fd);
89   GNUNET_free (h);
90   return err;
91 }
92
93
94 /**
95  * Read the contents of a binary file into a buffer.
96  *
97  * @param h handle to an open file
98  * @param what describes what is being read (for error message creation)
99  * @param result the buffer to write the result to
100  * @param len the number of bytes to read
101  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
102  */
103 int
104 GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, const char *what,
105                  void *result, size_t len)
106 {
107   char *dst = result;
108   size_t min;
109   size_t pos;
110   ssize_t ret;
111
112   if (h->emsg != NULL)
113     return GNUNET_SYSERR;
114   pos = 0;
115   do
116   {
117     /* first, use buffer */
118     min = h->have - h->pos;
119     if (min > 0)
120     {
121       if (min > len - pos)
122         min = len - pos;
123       memcpy (&dst[pos], &h->buffer[h->pos], min);
124       h->pos += min;
125       pos += min;
126     }
127     if (pos == len)
128       return GNUNET_OK;         /* done! */
129     GNUNET_assert (h->have == h->pos);
130     /* fill buffer */
131     ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size);
132     if (ret == -1)
133     {
134       GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what,
135                        STRERROR (errno));
136       return GNUNET_SYSERR;
137     }
138     if (ret == 0)
139     {
140       GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what,
141                        _("End of file"));
142       return GNUNET_SYSERR;
143     }
144     h->pos = 0;
145     h->have = ret;
146   }
147   while (pos < len);            /* should always be true */
148   return GNUNET_OK;
149 }
150
151
152 /**
153  * Read the contents of a binary file into a buffer.
154  *
155  * @param h handle to an open file
156  * @param file name of the source file
157  * @param line line number in the source file
158  * @param result the buffer to write the result to
159  * @param len the number of bytes to read
160  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
161  */
162 int
163 GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, const char *file, int line,
164                     void *result, size_t len)
165 {
166   char what[1024];
167
168   GNUNET_snprintf (what, sizeof (what), "%s:%d", file, line);
169   return GNUNET_BIO_read (h, what, result, len);
170 }
171
172
173 /**
174  * Read 0-terminated string from a file.
175  *
176  * @param h handle to an open file
177  * @param what describes what is being read (for error message creation)
178  * @param result the buffer to store a pointer to the (allocated) string to
179  *        (note that *result could be set to NULL as well)
180  * @param maxLen maximum allowed length for the string
181  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
182  */
183 int
184 GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, const char *what,
185                         char **result, size_t maxLen)
186 {
187   char *buf;
188   uint32_t big;
189
190   if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big))
191   {
192     GNUNET_free_non_null (h->emsg);
193     GNUNET_asprintf (&h->emsg, _("Error reading length of string `%s'"), what);
194     return GNUNET_SYSERR;
195   }
196   if (big == 0)
197   {
198     *result = NULL;
199     return GNUNET_OK;
200   }
201   if (big > maxLen)
202   {
203     GNUNET_asprintf (&h->emsg, _("String `%s' longer than allowed (%u > %u)"),
204                      what, big, maxLen);
205     return GNUNET_SYSERR;
206   }
207   buf = GNUNET_malloc (big);
208   *result = buf;
209   buf[--big] = '\0';
210   if (big == 0)
211     return GNUNET_OK;
212   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
213   {
214     GNUNET_free (buf);
215     *result = NULL;
216     return GNUNET_SYSERR;
217   }
218   return GNUNET_OK;
219 }
220
221
222 /**
223  * Read metadata container from a file.
224  *
225  * @param h handle to an open file
226  * @param what describes what is being read (for error message creation)
227  * @param result the buffer to store a pointer to the (allocated) metadata
228  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
229  */
230 int
231 GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, const char *what,
232                            struct GNUNET_CONTAINER_MetaData **result)
233 {
234   uint32_t size;
235   char *buf;
236   struct GNUNET_CONTAINER_MetaData *meta;
237
238   if (GNUNET_BIO_read_int32 (h, (int32_t *) & size) != GNUNET_OK)
239     return GNUNET_SYSERR;
240   if (size == 0)
241   {
242     *result = NULL;
243     return GNUNET_OK;
244   }
245   if (size > MAX_META_DATA)
246   {
247     GNUNET_asprintf (&h->emsg,
248                      _("Serialized metadata `%s' larger than allowed (%u>%u)"),
249                      what, size, MAX_META_DATA);
250     return GNUNET_SYSERR;
251   }
252   buf = GNUNET_malloc (size);
253   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size))
254   {
255     GNUNET_free (buf);
256     return GNUNET_SYSERR;
257   }
258   meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size);
259   if (meta == NULL)
260   {
261     GNUNET_free (buf);
262     GNUNET_asprintf (&h->emsg, _("Metadata `%s' failed to deserialize"), what);
263     return GNUNET_SYSERR;
264   }
265   GNUNET_free (buf);
266   *result = meta;
267   return GNUNET_OK;
268 }
269
270
271 /**
272  * Read an (u)int32_t.
273  *
274  * @param h hande to open file
275  * @param file name of the source file
276  * @param line line number in the source file
277  * @param i address of 32-bit integer to read
278  * @return GNUNET_OK on success, GNUNET_SYSERR on error
279  */
280 int
281 GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file,
282                          int line, int32_t * i)
283 {
284   int32_t big;
285
286   if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int32_t)))
287     return GNUNET_SYSERR;
288   *i = ntohl (big);
289   return GNUNET_OK;
290 }
291
292
293 /**
294  * Read an (u)int64_t.
295  *
296  * @param h hande to open file
297  * @param file name of the source file
298  * @param line line number in the source file
299  * @param i address of 64-bit integer to read
300  * @return GNUNET_OK on success, GNUNET_SYSERR on error
301  */
302 int
303 GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, const char *file,
304                          int line, int64_t * i)
305 {
306   int64_t big;
307
308   if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int64_t)))
309     return GNUNET_SYSERR;
310   *i = GNUNET_ntohll (big);
311   return GNUNET_OK;
312 }
313
314
315 /**
316  * Handle for buffered writing.
317  */
318 struct GNUNET_BIO_WriteHandle
319 {
320   struct GNUNET_DISK_FileHandle *fd;
321   char *buffer;
322   size_t have;
323   size_t size;
324 };
325
326
327 /**
328  * Open a file for writing.
329  *
330  * @param fn file name to be opened
331  * @return IO handle on success, NULL on error
332  */
333 struct GNUNET_BIO_WriteHandle *
334 GNUNET_BIO_write_open (const char *fn)
335 {
336   struct GNUNET_DISK_FileHandle *fd;
337   struct GNUNET_BIO_WriteHandle *h;
338
339   fd = GNUNET_DISK_file_open (fn,
340                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
341                               | GNUNET_DISK_OPEN_CREATE,
342                               GNUNET_DISK_PERM_USER_READ |
343                               GNUNET_DISK_PERM_USER_WRITE);
344   if (NULL == fd)
345     return NULL;
346   h = GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
347   h->buffer = (char *) &h[1];
348   h->size = BIO_BUFFER_SIZE;
349   h->fd = fd;
350
351   return h;
352 }
353
354
355 /**
356  * Close an open file for writing.
357  *
358  * @param h file handle
359  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
360  */
361 int
362 GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h)
363 {
364   ssize_t wrt;
365   int ret;
366
367   if (NULL == h->fd)
368   {
369     ret = GNUNET_SYSERR;
370   }
371   else
372   {
373     wrt = GNUNET_DISK_file_write (h->fd, h->buffer, h->have);
374     if (wrt == h->have)
375       ret = GNUNET_OK;
376     else
377       ret = GNUNET_SYSERR;
378     GNUNET_DISK_file_close (h->fd);
379   }
380   GNUNET_free (h);
381   return ret;
382 }
383
384
385 /**
386  * Write a buffer to a file.
387  *
388  * @param h handle to open file
389  * @param buffer the data to write
390  * @param n number of bytes to write
391  * @return GNUNET_OK on success, GNUNET_SYSERR on error
392  */
393 int
394 GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer,
395                   size_t n)
396 {
397   const char *src = buffer;
398   size_t min;
399   size_t pos;
400   ssize_t ret;
401
402   if (NULL == h->fd)
403     return GNUNET_SYSERR;
404   pos = 0;
405   do
406   {
407     /* first, just use buffer */
408     min = h->size - h->have;
409     if (min > n - pos)
410       min = n - pos;
411     memcpy (&h->buffer[h->have], &src[pos], min);
412     pos += min;
413     h->have += min;
414     if (pos == n)
415       return GNUNET_OK;         /* done */
416     GNUNET_assert (h->have == h->size);
417     ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->size);
418     if (ret != h->size)
419     {
420       GNUNET_DISK_file_close (h->fd);
421       h->fd = NULL;
422       return GNUNET_SYSERR;     /* error */
423     }
424     h->have = 0;
425   }
426   while (pos < n);              /* should always be true */
427   GNUNET_break (0);
428   return GNUNET_OK;
429 }
430
431
432 /**
433  * Write a string to a file.
434  *
435  * @param h handle to open file
436  * @param s string to write (can be NULL)
437  * @return GNUNET_OK on success, GNUNET_SYSERR on error
438  */
439 int
440 GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s)
441 {
442   uint32_t slen;
443
444   slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1);
445   if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen))
446     return GNUNET_SYSERR;
447   if (0 != slen)
448     return GNUNET_BIO_write (h, s, slen - 1);
449   return GNUNET_OK;
450 }
451
452
453 /**
454  * Write metadata container to a file.
455  *
456  * @param h handle to open file
457  * @param m metadata to write
458  * @return GNUNET_OK on success, GNUNET_SYSERR on error
459  */
460 int
461 GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
462                             const struct GNUNET_CONTAINER_MetaData *m)
463 {
464   ssize_t size;
465   char *buf;
466
467   if (m == NULL)
468     return GNUNET_BIO_write_int32 (h, 0);
469   buf = NULL;
470   size =
471       GNUNET_CONTAINER_meta_data_serialize (m, &buf, MAX_META_DATA,
472                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
473   if (size == -1)
474   {
475     GNUNET_free (buf);
476     return GNUNET_SYSERR;
477   }
478   if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) ||
479       (GNUNET_OK != GNUNET_BIO_write (h, buf, size)))
480   {
481     GNUNET_free (buf);
482     return GNUNET_SYSERR;
483   }
484   GNUNET_free (buf);
485   return GNUNET_OK;
486 }
487
488
489 /**
490  * Write an (u)int32_t.
491  *
492  * @param h hande to open file
493  * @param i address of 32-bit integer to write
494  * @return GNUNET_OK on success, GNUNET_SYSERR on error
495  */
496 int
497 GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i)
498 {
499   int32_t big;
500
501   big = htonl (i);
502   return GNUNET_BIO_write (h, &big, sizeof (int32_t));
503 }
504
505
506 /**
507  * Write an (u)int64_t.
508  *
509  * @param h hande to open file
510  * @param i address of 64-bit integer to write
511  * @return GNUNET_OK on success, GNUNET_SYSERR on error
512  */
513 int
514 GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i)
515 {
516   int64_t big;
517
518   big = GNUNET_htonll (i);
519   return GNUNET_BIO_write (h, &big, sizeof (int64_t));
520 }
521
522
523 /* end of bio.c */