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