Merge branch 'master' of 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 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      SPDX-License-Identifier: AGPL3.0-or-later
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-bio",__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],
166                      &h->buffer[h->pos],
167                      min);
168       h->pos += min;
169       pos += min;
170     }
171     if (pos == len)
172       return GNUNET_OK;         /* done! */
173     GNUNET_assert (((off_t) h->have) == h->pos);
174     /* fill buffer */
175     ret = GNUNET_DISK_file_read (h->fd,
176                                  h->buffer,
177                                  h->size);
178     if (-1 == ret)
179     {
180       GNUNET_asprintf (&h->emsg,
181                        _("Error reading `%s': %s"),
182                        what,
183                        STRERROR (errno));
184       return GNUNET_SYSERR;
185     }
186     if (0 == ret)
187     {
188       GNUNET_asprintf (&h->emsg,
189                        _("Error reading `%s': %s"),
190                        what,
191                        _("End of file"));
192       return GNUNET_SYSERR;
193     }
194     h->pos = 0;
195     h->have = ret;
196   }
197   while (pos < len);            /* should always be true */
198   return GNUNET_OK;
199 }
200
201
202 /**
203  * Read the contents of a binary file into a buffer.
204  *
205  * @param h handle to an open file
206  * @param file name of the source file
207  * @param line line number in the source file
208  * @param result the buffer to write the result to
209  * @param len the number of bytes to read
210  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
211  */
212 int
213 GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h,
214                     const char *file,
215                     int line,
216                     void *result,
217                     size_t len)
218 {
219   char what[PATH_MAX + 1024];
220
221   GNUNET_snprintf (what, sizeof (what), "%s:%d", file, line);
222   return GNUNET_BIO_read (h, what, result, len);
223 }
224
225
226 /**
227  * Read 0-terminated string from a file.
228  *
229  * @param h handle to an open file
230  * @param what describes what is being read (for error message creation)
231  * @param result the buffer to store a pointer to the (allocated) string to
232  *        (note that *result could be set to NULL as well)
233  * @param max_length maximum allowed length for the string
234  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
235  */
236 int
237 GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h,
238                         const char *what,
239                         char **result,
240                         size_t max_length)
241 {
242   char *buf;
243   uint32_t big;
244
245   if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big))
246   {
247     GNUNET_free_non_null (h->emsg);
248     GNUNET_asprintf (&h->emsg, _("Error reading length of string `%s'"), what);
249     return GNUNET_SYSERR;
250   }
251   if (0 == big)
252   {
253     *result = NULL;
254     return GNUNET_OK;
255   }
256   if (big > max_length)
257   {
258     GNUNET_asprintf (&h->emsg, _("String `%s' longer than allowed (%u > %u)"),
259                      what, big, max_length);
260     return GNUNET_SYSERR;
261   }
262   buf = GNUNET_malloc (big);
263   *result = buf;
264   buf[--big] = '\0';
265   if (0 == big)
266     return GNUNET_OK;
267   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
268   {
269     GNUNET_free (buf);
270     *result = NULL;
271     return GNUNET_SYSERR;
272   }
273   return GNUNET_OK;
274 }
275
276
277 /**
278  * Read metadata container from a file.
279  *
280  * @param h handle to an open file
281  * @param what describes what is being read (for error message creation)
282  * @param result the buffer to store a pointer to the (allocated) metadata
283  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
284  */
285 int
286 GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
287                            const char *what,
288                            struct GNUNET_CONTAINER_MetaData **result)
289 {
290   uint32_t size;
291   char *buf;
292   struct GNUNET_CONTAINER_MetaData *meta;
293
294   if (GNUNET_OK !=
295       GNUNET_BIO_read_int32 (h,
296                              (int32_t *) & size))
297     return GNUNET_SYSERR;
298   if (size == 0)
299   {
300     *result = NULL;
301     return GNUNET_OK;
302   }
303   if (size > MAX_META_DATA)
304   {
305     GNUNET_asprintf (&h->emsg,
306                      _("Serialized metadata `%s' larger than allowed (%u>%u)"),
307                      what,
308                      size,
309                      MAX_META_DATA);
310     return GNUNET_SYSERR;
311   }
312   buf = GNUNET_malloc (size);
313   if (GNUNET_OK !=
314       GNUNET_BIO_read (h,
315                        what,
316                        buf,
317                        size))
318   {
319     GNUNET_free (buf);
320     return GNUNET_SYSERR;
321   }
322   meta = GNUNET_CONTAINER_meta_data_deserialize (buf,
323                                                  size);
324   if (NULL == meta)
325   {
326     GNUNET_free (buf);
327     GNUNET_asprintf (&h->emsg,
328                      _("Metadata `%s' failed to deserialize"),
329                      what);
330     return GNUNET_SYSERR;
331   }
332   GNUNET_free (buf);
333   *result = meta;
334   return GNUNET_OK;
335 }
336
337
338 /**
339  * Read an (u)int32_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 32-bit integer to read
345  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
346  */
347 int
348 GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h,
349                          const char *file,
350                          int line,
351                          int32_t * i)
352 {
353   int32_t big;
354
355   if (GNUNET_OK !=
356       GNUNET_BIO_read_fn (h,
357                           file,
358                           line,
359                           &big,
360                           sizeof (int32_t)))
361     return GNUNET_SYSERR;
362   *i = ntohl (big);
363   return GNUNET_OK;
364 }
365
366
367 /**
368  * Read an (u)int64_t.
369  *
370  * @param h hande to open file
371  * @param file name of the source file
372  * @param line line number in the source file
373  * @param i address of 64-bit integer to read
374  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
375  */
376 int
377 GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h,
378                          const char *file,
379                          int line,
380                          int64_t *i)
381 {
382   int64_t big;
383
384   if (GNUNET_OK !=
385       GNUNET_BIO_read_fn (h,
386                           file,
387                           line,
388                           &big,
389                           sizeof (int64_t)))
390     return GNUNET_SYSERR;
391   *i = GNUNET_ntohll (big);
392   return GNUNET_OK;
393 }
394
395
396 /**
397  * Handle for buffered writing.
398  */
399 struct GNUNET_BIO_WriteHandle
400 {
401   /**
402    * Underlying file handle.
403    */
404   struct GNUNET_DISK_FileHandle *fd;
405
406   /**
407    * I/O buffer.  Do not free, allocated at the end of the struct.
408    */
409   char *buffer;
410
411   /**
412    * Number of bytes already in @e buffer.
413    */
414   size_t have;
415
416   /**
417    * Total size of @e buffer.
418    */
419   size_t size;
420 };
421
422
423 /**
424  * Open a file for writing.
425  *
426  * @param fn file name to be opened
427  * @return IO handle on success, NULL on error
428  */
429 struct GNUNET_BIO_WriteHandle *
430 GNUNET_BIO_write_open (const char *fn)
431 {
432   struct GNUNET_DISK_FileHandle *fd;
433   struct GNUNET_BIO_WriteHandle *h;
434
435   fd = GNUNET_DISK_file_open (fn,
436                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
437                               | GNUNET_DISK_OPEN_CREATE,
438                               GNUNET_DISK_PERM_USER_READ |
439                               GNUNET_DISK_PERM_USER_WRITE);
440   if (NULL == fd)
441     return NULL;
442   h = GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
443   h->buffer = (char *) &h[1];
444   h->size = BIO_BUFFER_SIZE;
445   h->fd = fd;
446   return h;
447 }
448
449
450 /**
451  * Close an open file for writing.
452  *
453  * @param h file handle
454  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
455  */
456 int
457 GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h)
458 {
459   int ret;
460
461   ret = GNUNET_SYSERR;
462   if ( (NULL != h->fd) &&
463        (GNUNET_OK == (ret = GNUNET_BIO_flush (h))) )
464     GNUNET_DISK_file_close (h->fd);
465   GNUNET_free (h);
466   return ret;
467 }
468
469
470 /**
471  * Force a buffered writer to flush its buffer
472  *
473  * @param h the writer handle
474  * @return #GNUNET_OK upon success.  Upon failure #GNUNET_SYSERR is returned and
475  *           the file is closed
476  */
477 int
478 GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h)
479 {
480   ssize_t ret;
481
482   ret = GNUNET_DISK_file_write (h->fd,
483                                 h->buffer,
484                                 h->have);
485   if (ret != (ssize_t) h->have)
486   {
487     GNUNET_DISK_file_close (h->fd);
488     h->fd = NULL;
489     return GNUNET_SYSERR;     /* error */
490   }
491   h->have = 0;
492   return GNUNET_OK;
493 }
494
495
496 /**
497  * Write a buffer to a file.
498  *
499  * @param h handle to open file
500  * @param buffer the data to write
501  * @param n number of bytes to write
502  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
503  */
504 int
505 GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h,
506                   const void *buffer,
507                   size_t n)
508 {
509   const char *src = buffer;
510   size_t min;
511   size_t pos;
512
513   if (NULL == h->fd)
514     return GNUNET_SYSERR;
515   pos = 0;
516   do
517   {
518     /* first, just use buffer */
519     min = h->size - h->have;
520     if (min > n - pos)
521       min = n - pos;
522     GNUNET_memcpy (&h->buffer[h->have],
523                    &src[pos],
524                    min);
525     pos += min;
526     h->have += min;
527     if (pos == n)
528       return GNUNET_OK;         /* done */
529     GNUNET_assert (h->have == h->size);
530     if (GNUNET_OK != GNUNET_BIO_flush (h))
531       return GNUNET_SYSERR;     /* error */
532   }
533   while (pos < n);              /* should always be true */
534   GNUNET_break (0);
535   return GNUNET_OK;
536 }
537
538
539 /**
540  * Write a string to a file.
541  *
542  * @param h handle to open file
543  * @param s string to write (can be NULL)
544  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
545  */
546 int
547 GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h,
548                          const char *s)
549 {
550   uint32_t slen;
551
552   slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1);
553   if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen))
554     return GNUNET_SYSERR;
555   if (0 != slen)
556     return GNUNET_BIO_write (h, s, slen - 1);
557   return GNUNET_OK;
558 }
559
560
561 /**
562  * Write metadata container to a file.
563  *
564  * @param h handle to open file
565  * @param m metadata to write
566  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
567  */
568 int
569 GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
570                             const struct GNUNET_CONTAINER_MetaData *m)
571 {
572   ssize_t size;
573   char *buf;
574
575   if (m == NULL)
576     return GNUNET_BIO_write_int32 (h, 0);
577   buf = NULL;
578   size =
579       GNUNET_CONTAINER_meta_data_serialize (m, &buf, MAX_META_DATA,
580                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
581   if (size == -1)
582   {
583     GNUNET_free (buf);
584     return GNUNET_SYSERR;
585   }
586   if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) ||
587       (GNUNET_OK != GNUNET_BIO_write (h, buf, size)))
588   {
589     GNUNET_free (buf);
590     return GNUNET_SYSERR;
591   }
592   GNUNET_free (buf);
593   return GNUNET_OK;
594 }
595
596
597 /**
598  * Write an (u)int32_t.
599  *
600  * @param h hande to open file
601  * @param i 32-bit integer to write
602  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
603  */
604 int
605 GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h,
606                         int32_t i)
607 {
608   int32_t big;
609
610   big = htonl (i);
611   return GNUNET_BIO_write (h, &big, sizeof (int32_t));
612 }
613
614
615 /**
616  * Write an (u)int64_t.
617  *
618  * @param h hande to open file
619  * @param i 64-bit integer to write
620  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
621  */
622 int
623 GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h,
624                         int64_t i)
625 {
626   int64_t big;
627
628   big = GNUNET_htonll (i);
629   return GNUNET_BIO_write (h, &big, sizeof (int64_t));
630 }
631
632
633 /* end of bio.c */