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