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