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