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