use NULL value in load_path_suffix to NOT load any files
[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, char **emsg)
120 {
121   int err;
122
123   err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR;
124   if (emsg != NULL)
125     *emsg = h->emsg;
126   else
127     GNUNET_free_non_null (h->emsg);
128   GNUNET_DISK_file_close (h->fd);
129   GNUNET_free (h);
130   return err;
131 }
132
133
134 /**
135  * Read the contents of a binary file into a buffer.
136  *
137  * @param h handle to an open file
138  * @param what describes what is being read (for error message creation)
139  * @param result the buffer to write the result to
140  * @param len the number of bytes to read
141  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
142  */
143 int
144 GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h,
145                  const char *what,
146                  void *result,
147                  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 (((off_t) 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,
255                      _ ("String `%s' longer than allowed (%u > %u)"),
256                      what,
257                      big,
258                      max_length);
259     return GNUNET_SYSERR;
260   }
261   buf = GNUNET_malloc (big);
262   *result = buf;
263   buf[--big] = '\0';
264   if (0 == big)
265     return GNUNET_OK;
266   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big))
267   {
268     GNUNET_free (buf);
269     *result = NULL;
270     return GNUNET_SYSERR;
271   }
272   return GNUNET_OK;
273 }
274
275
276 /**
277  * Read metadata container from a file.
278  *
279  * @param h handle to an open file
280  * @param what describes what is being read (for error message creation)
281  * @param result the buffer to store a pointer to the (allocated) metadata
282  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
283  */
284 int
285 GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h,
286                            const char *what,
287                            struct GNUNET_CONTAINER_MetaData **result)
288 {
289   uint32_t size;
290   char *buf;
291   struct GNUNET_CONTAINER_MetaData *meta;
292
293   if (GNUNET_OK != GNUNET_BIO_read_int32 (h, (int32_t *) &size))
294     return GNUNET_SYSERR;
295   if (size == 0)
296   {
297     *result = NULL;
298     return GNUNET_OK;
299   }
300   if (size > MAX_META_DATA)
301   {
302     GNUNET_asprintf (&h->emsg,
303                      _ ("Serialized metadata `%s' larger than allowed (%u>%u)"),
304                      what,
305                      size,
306                      MAX_META_DATA);
307     return GNUNET_SYSERR;
308   }
309   buf = GNUNET_malloc (size);
310   if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size))
311   {
312     GNUNET_free (buf);
313     return GNUNET_SYSERR;
314   }
315   meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size);
316   if (NULL == meta)
317   {
318     GNUNET_free (buf);
319     GNUNET_asprintf (&h->emsg, _ ("Metadata `%s' failed to deserialize"), what);
320     return GNUNET_SYSERR;
321   }
322   GNUNET_free (buf);
323   *result = meta;
324   return GNUNET_OK;
325 }
326
327
328 /**
329  * Read an (u)int32_t.
330  *
331  * @param h hande to open file
332  * @param file name of the source file
333  * @param line line number in the source file
334  * @param i address of 32-bit integer to read
335  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
336  */
337 int
338 GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h,
339                          const char *file,
340                          int line,
341                          int32_t *i)
342 {
343   int32_t big;
344
345   if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof(int32_t)))
346     return GNUNET_SYSERR;
347   *i = ntohl (big);
348   return GNUNET_OK;
349 }
350
351
352 /**
353  * Read an (u)int64_t.
354  *
355  * @param h hande to open file
356  * @param file name of the source file
357  * @param line line number in the source file
358  * @param i address of 64-bit integer to read
359  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
360  */
361 int
362 GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h,
363                          const char *file,
364                          int line,
365                          int64_t *i)
366 {
367   int64_t big;
368
369   if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof(int64_t)))
370     return GNUNET_SYSERR;
371   *i = GNUNET_ntohll (big);
372   return GNUNET_OK;
373 }
374
375
376 /**
377  * Handle for buffered writing.
378  */
379 struct GNUNET_BIO_WriteHandle
380 {
381   /**
382    * Underlying file handle.
383    */
384   struct GNUNET_DISK_FileHandle *fd;
385
386   /**
387    * I/O buffer.  Do not free, allocated at the end of the struct.
388    */
389   char *buffer;
390
391   /**
392    * Number of bytes already in @e buffer.
393    */
394   size_t have;
395
396   /**
397    * Total size of @e buffer.
398    */
399   size_t size;
400 };
401
402
403 /**
404  * Open a file for writing.
405  *
406  * @param fn file name to be opened
407  * @return IO handle on success, NULL on error
408  */
409 struct GNUNET_BIO_WriteHandle *
410 GNUNET_BIO_write_open (const char *fn)
411 {
412   struct GNUNET_DISK_FileHandle *fd;
413   struct GNUNET_BIO_WriteHandle *h;
414
415   fd =
416     GNUNET_DISK_file_open (fn,
417                            GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
418                            | GNUNET_DISK_OPEN_CREATE,
419                            GNUNET_DISK_PERM_USER_READ
420                            | GNUNET_DISK_PERM_USER_WRITE);
421   if (NULL == fd)
422     return NULL;
423   h = GNUNET_malloc (sizeof(struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE);
424   h->buffer = (char *) &h[1];
425   h->size = BIO_BUFFER_SIZE;
426   h->fd = fd;
427   return h;
428 }
429
430
431 /**
432  * Close an open file for writing.
433  *
434  * @param h file handle
435  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
436  */
437 int
438 GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h)
439 {
440   int ret;
441
442   ret = GNUNET_SYSERR;
443   if ((NULL != h->fd) && (GNUNET_OK == (ret = GNUNET_BIO_flush (h))))
444     GNUNET_DISK_file_close (h->fd);
445   GNUNET_free (h);
446   return ret;
447 }
448
449
450 /**
451  * Force a buffered writer to flush its buffer
452  *
453  * @param h the writer handle
454  * @return #GNUNET_OK upon success.  Upon failure #GNUNET_SYSERR is returned and
455  *           the file is closed
456  */
457 int
458 GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h)
459 {
460   ssize_t ret;
461
462   ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->have);
463   if (ret != (ssize_t) h->have)
464   {
465     GNUNET_DISK_file_close (h->fd);
466     h->fd = NULL;
467     return GNUNET_SYSERR;   /* error */
468   }
469   h->have = 0;
470   return GNUNET_OK;
471 }
472
473
474 /**
475  * Write a buffer to a file.
476  *
477  * @param h handle to open file
478  * @param buffer the data to write
479  * @param n number of bytes to write
480  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
481  */
482 int
483 GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h,
484                   const void *buffer,
485                   size_t n)
486 {
487   const char *src = buffer;
488   size_t min;
489   size_t pos;
490
491   if (NULL == h->fd)
492     return GNUNET_SYSERR;
493   pos = 0;
494   do
495   {
496     /* first, just use buffer */
497     min = h->size - h->have;
498     if (min > n - pos)
499       min = n - pos;
500     GNUNET_memcpy (&h->buffer[h->have], &src[pos], min);
501     pos += min;
502     h->have += min;
503     if (pos == n)
504       return GNUNET_OK;   /* done */
505     GNUNET_assert (h->have == h->size);
506     if (GNUNET_OK != GNUNET_BIO_flush (h))
507       return GNUNET_SYSERR;   /* error */
508   }
509   while (pos < n);   /* should always be true */
510   GNUNET_break (0);
511   return GNUNET_OK;
512 }
513
514
515 /**
516  * Write a string to a file.
517  *
518  * @param h handle to open file
519  * @param s string to write (can be NULL)
520  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
521  */
522 int
523 GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s)
524 {
525   uint32_t slen;
526
527   slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1);
528   if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen))
529     return GNUNET_SYSERR;
530   if (0 != slen)
531     return GNUNET_BIO_write (h, s, slen - 1);
532   return GNUNET_OK;
533 }
534
535
536 /**
537  * Write metadata container to a file.
538  *
539  * @param h handle to open file
540  * @param m metadata to write
541  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
542  */
543 int
544 GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h,
545                             const struct GNUNET_CONTAINER_MetaData *m)
546 {
547   ssize_t size;
548   char *buf;
549
550   if (m == NULL)
551     return GNUNET_BIO_write_int32 (h, 0);
552   buf = NULL;
553   size = GNUNET_CONTAINER_meta_data_serialize (
554     m,
555     &buf,
556     MAX_META_DATA,
557     GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
558   if (size == -1)
559   {
560     GNUNET_free (buf);
561     return GNUNET_SYSERR;
562   }
563   if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) ||
564       (GNUNET_OK != GNUNET_BIO_write (h, buf, size)))
565   {
566     GNUNET_free (buf);
567     return GNUNET_SYSERR;
568   }
569   GNUNET_free (buf);
570   return GNUNET_OK;
571 }
572
573
574 /**
575  * Write an (u)int32_t.
576  *
577  * @param h hande to open file
578  * @param i 32-bit integer to write
579  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
580  */
581 int
582 GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i)
583 {
584   int32_t big;
585
586   big = htonl (i);
587   return GNUNET_BIO_write (h, &big, sizeof(int32_t));
588 }
589
590
591 /**
592  * Write an (u)int64_t.
593  *
594  * @param h hande to open file
595  * @param i 64-bit integer to write
596  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
597  */
598 int
599 GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i)
600 {
601   int64_t big;
602
603   big = GNUNET_htonll (i);
604   return GNUNET_BIO_write (h, &big, sizeof(int64_t));
605 }
606
607
608 /* end of bio.c */