Tizen 2.0 Release
[external/libgnutls26.git] / lib / opencdk / stream.c
1 /* stream.c - The stream implementation
2  * Copyright (C) 2002, 2003, 2007, 2008, 2010 Free Software Foundation,
3  * Inc.
4  *
5  * Author: Timo Schulz
6  *
7  * This file is part of OpenCDK.
8  *
9  * The OpenCDK library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <assert.h>
29 #include <stdio.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include "opencdk.h"
39 #include "main.h"
40 #include "filters.h"
41 #include "stream.h"
42 #include "types.h"
43
44 /* This is the maximal amount of bytes we map. */
45 #define MAX_MAP_SIZE 16777216
46
47 static cdk_error_t stream_flush (cdk_stream_t s);
48 static cdk_error_t stream_filter_write (cdk_stream_t s);
49 static int stream_cache_flush (cdk_stream_t s, FILE * fp);
50 struct stream_filter_s *filter_add (cdk_stream_t s, filter_fnct_t fnc,
51                                     int type);
52
53
54 /* FIXME: The read/write/putc/getc function cannot directly
55           return an error code. It is stored in an error variable
56           inside the string. Right now there is no code to
57           return the error code or to reset it. */
58
59 /**
60  * cdk_stream_open:
61  * @file: The file to open
62  * @ret_s: The new STREAM object
63  * 
64  * Creates a new stream based on an existing file. The stream is
65  * opened in read-only mode.
66  **/
67 cdk_error_t
68 cdk_stream_open (const char *file, cdk_stream_t * ret_s)
69 {
70   return _cdk_stream_open_mode (file, "rb", ret_s);
71 }
72
73
74 /* Helper function to allow to open a stream in different modes. */
75 cdk_error_t
76 _cdk_stream_open_mode (const char *file, const char *mode,
77                        cdk_stream_t * ret_s)
78 {
79   cdk_stream_t s;
80
81   if (!file || !ret_s)
82     {
83       gnutls_assert ();
84       return CDK_Inv_Value;
85     }
86
87   _gnutls_read_log ("open stream `%s'\n", file);
88   *ret_s = NULL;
89   s = cdk_calloc (1, sizeof *s);
90   if (!s)
91     {
92       gnutls_assert ();
93       return CDK_Out_Of_Core;
94     }
95   s->fname = cdk_strdup (file);
96   if (!s->fname)
97     {
98       cdk_free (s);
99       gnutls_assert ();
100       return CDK_Out_Of_Core;
101     }
102   s->fp = fopen (file, mode);
103   if (!s->fp)
104     {
105       cdk_free (s->fname);
106       cdk_free (s);
107       gnutls_assert ();
108       return CDK_File_Error;
109     }
110   _gnutls_read_log ("open stream fd=%d\n", fileno (s->fp));
111   s->flags.write = 0;
112   *ret_s = s;
113   return 0;
114 }
115
116
117 /**
118  * cdk_stream_new_from_cbs:
119  * @cbs: the callback context with all user callback functions
120  * @opa: opaque handle which is passed to all callbacks.
121  * @ret_s: the allocated stream
122  * 
123  * This function creates a stream which uses user callback
124  * for the core operations (open, close, read, write, seek).
125  */
126 cdk_error_t
127 cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
128                          cdk_stream_t * ret_s)
129 {
130   cdk_stream_t s;
131
132   if (!cbs || !opa || !ret_s)
133     {
134       gnutls_assert ();
135       return CDK_Inv_Value;
136     }
137
138   *ret_s = NULL;
139   s = cdk_calloc (1, sizeof *s);
140   if (!s)
141     {
142       gnutls_assert ();
143       return CDK_Out_Of_Core;
144     }
145
146   s->cbs.read = cbs->read;
147   s->cbs.write = cbs->write;
148   s->cbs.seek = cbs->seek;
149   s->cbs.release = cbs->release;
150   s->cbs.open = cbs->open;
151   s->cbs_hd = opa;
152   *ret_s = s;
153
154   /* If there is a user callback for open, we need to call it
155      here because read/write expects an open stream. */
156   if (s->cbs.open)
157     return s->cbs.open (s->cbs_hd);
158   return 0;
159 }
160
161
162 /**
163  * cdk_stream_new: 
164  * @file: The name of the new file
165  * @ret_s: The new STREAM object
166  * 
167  * Create a new stream into the given file.
168  **/
169 cdk_error_t
170 cdk_stream_new (const char *file, cdk_stream_t * ret_s)
171 {
172   cdk_stream_t s;
173
174   if (!ret_s)
175     {
176       gnutls_assert ();
177       return CDK_Inv_Value;
178     }
179
180   _gnutls_read_log ("new stream `%s'\n", file ? file : "[temp]");
181   *ret_s = NULL;
182   s = cdk_calloc (1, sizeof *s);
183   if (!s)
184     {
185       gnutls_assert ();
186       return CDK_Out_Of_Core;
187     }
188   s->flags.write = 1;
189   if (!file)
190     s->flags.temp = 1;
191   else
192     {
193       s->fname = cdk_strdup (file);
194       if (!s->fname)
195         {
196           cdk_free (s);
197           gnutls_assert ();
198           return CDK_Out_Of_Core;
199         }
200     }
201   s->fp = _cdk_tmpfile ();
202   if (!s->fp)
203     {
204       cdk_free (s->fname);
205       cdk_free (s);
206       gnutls_assert ();
207       return CDK_File_Error;
208     }
209   _gnutls_read_log ("new stream fd=%d\n", fileno (s->fp));
210   *ret_s = s;
211   return 0;
212 }
213
214 /**
215  * cdk_stream_create: 
216  * @file: the filename
217  * @ret_s: the object
218  *
219  * Creates a new stream.
220  * The difference to cdk_stream_new is, that no filtering can be used with
221  * this kind of stream and everything is written directly to the stream.
222  **/
223 cdk_error_t
224 cdk_stream_create (const char *file, cdk_stream_t * ret_s)
225 {
226   cdk_stream_t s;
227
228   if (!file || !ret_s)
229     {
230       gnutls_assert ();
231       return CDK_Inv_Value;
232     }
233
234   _gnutls_read_log ("create stream `%s'\n", file);
235   *ret_s = NULL;
236   s = cdk_calloc (1, sizeof *s);
237   if (!s)
238     {
239       gnutls_assert ();
240       return CDK_Out_Of_Core;
241     }
242   s->flags.write = 1;
243   s->flags.filtrated = 1;
244   s->fname = cdk_strdup (file);
245   if (!s->fname)
246     {
247       cdk_free (s);
248       gnutls_assert ();
249       return CDK_Out_Of_Core;
250     }
251   s->fp = fopen (file, "w+b");
252   if (!s->fp)
253     {
254       cdk_free (s->fname);
255       cdk_free (s);
256       gnutls_assert ();
257       return CDK_File_Error;
258     }
259   _gnutls_read_log ("stream create fd=%d\n", fileno (s->fp));
260   *ret_s = s;
261   return 0;
262 }
263
264
265 /**
266  * cdk_stream_tmp_new:
267  * @r_out: the new temp stream.
268  * 
269  * Allocates a new tempory stream which is not associated with a file.
270  */
271 cdk_error_t
272 cdk_stream_tmp_new (cdk_stream_t * r_out)
273 {
274   return cdk_stream_new (NULL, r_out);
275 }
276
277
278
279 /**
280  * cdk_stream_tmp_from_mem:
281  * @buf: the buffer which shall be written to the temp stream.
282  * @buflen: how large the buffer is
283  * @r_out: the new stream with the given contents.
284  * 
285  * Creates a new tempory stream with the given contests.
286  */
287 cdk_error_t
288 cdk_stream_tmp_from_mem (const void *buf, size_t buflen, cdk_stream_t * r_out)
289 {
290   cdk_stream_t s;
291   cdk_error_t rc;
292   int nwritten;
293
294   *r_out = NULL;
295   rc = cdk_stream_tmp_new (&s);
296   if (rc)
297     {
298       gnutls_assert ();
299       return rc;
300     }
301
302   nwritten = cdk_stream_write (s, buf, buflen);
303   if (nwritten == EOF)
304     {
305       cdk_stream_close (s);
306       gnutls_assert ();
307       return s->error;
308     }
309   cdk_stream_seek (s, 0);
310   *r_out = s;
311   return 0;
312 }
313
314
315 cdk_error_t
316 _cdk_stream_fpopen (FILE * fp, unsigned write_mode, cdk_stream_t * ret_out)
317 {
318   cdk_stream_t s;
319
320   *ret_out = NULL;
321   s = cdk_calloc (1, sizeof *s);
322   if (!s)
323     {
324       gnutls_assert ();
325       return CDK_Out_Of_Core;
326     }
327
328   _gnutls_read_log ("stream ref fd=%d\n", fileno (fp));
329   s->fp = fp;
330   s->fp_ref = 1;
331   s->flags.filtrated = 1;
332   s->flags.write = write_mode;
333
334   *ret_out = s;
335   return 0;
336 }
337
338
339 cdk_error_t
340 _cdk_stream_append (const char *file, cdk_stream_t * ret_s)
341 {
342   cdk_stream_t s;
343   cdk_error_t rc;
344
345   if (!ret_s)
346     {
347       gnutls_assert ();
348       return CDK_Inv_Value;
349     }
350   *ret_s = NULL;
351
352   rc = _cdk_stream_open_mode (file, "a+b", &s);
353   if (rc)
354     {
355       gnutls_assert ();
356       return rc;
357     }
358
359   /* In the append mode, we need to write to the flag. */
360   s->flags.write = 1;
361   *ret_s = s;
362   return 0;
363 }
364
365 /**
366  * cdk_stream_is_compressed:
367  * @s: the stream
368  *
369  * Check whether stream is compressed.
370  *
371  * Returns: 0 if the stream is uncompressed, otherwise the compression
372  *   algorithm.
373  */
374 int
375 cdk_stream_is_compressed (cdk_stream_t s)
376 {
377   if (!s)
378     return 0;
379   return s->flags.compressed;
380 }
381
382 void
383 _cdk_stream_set_compress_algo (cdk_stream_t s, int algo)
384 {
385   if (!s)
386     return;
387   s->flags.compressed = algo;
388 }
389
390
391 cdk_error_t
392 cdk_stream_flush (cdk_stream_t s)
393 {
394   cdk_error_t rc;
395
396   if (!s)
397     {
398       gnutls_assert ();
399       return CDK_Inv_Value;
400     }
401
402   /* The user callback does not support flush */
403   if (s->cbs_hd)
404     return 0;
405
406   /* For read-only streams, no flush is needed. */
407   if (!s->flags.write)
408     return 0;
409
410   if (!s->flags.filtrated)
411     {
412       if (!cdk_stream_get_length (s))
413         return 0;
414       rc = cdk_stream_seek (s, 0);
415       if (!rc)
416         rc = stream_flush (s);
417       if (!rc)
418         rc = stream_filter_write (s);
419       s->flags.filtrated = 1;
420       if (rc)
421         {
422           s->error = rc;
423           gnutls_assert ();
424           return rc;
425         }
426     }
427   return 0;
428 }
429
430
431 void
432 cdk_stream_tmp_set_mode (cdk_stream_t s, int val)
433 {
434   if (s && s->flags.temp)
435     s->fmode = val;
436 }
437
438
439 /**
440  * cdk_stream_close:
441  * @s: The STREAM object.
442  *
443  * Close a stream and flush all buffers.  This function work different
444  * for read or write streams. When the stream is for reading, the
445  * filtering is already done and we can simply close the file and all
446  * buffers.  But for the case it's a write stream, we need to apply
447  * all registered filters now. The file is closed in the filter
448  * function and not here.
449  **/
450 cdk_error_t
451 cdk_stream_close (cdk_stream_t s)
452 {
453   struct stream_filter_s *f, *f2;
454   cdk_error_t rc;
455
456   if (!s)
457     {
458       gnutls_assert ();
459       return CDK_Inv_Value;
460     }
461
462   _gnutls_read_log ("close stream ref=%d `%s'\n",
463                     s->fp_ref, s->fname ? s->fname : "[temp]");
464
465   /* In the user callback mode, we call the release cb if possible
466      and just free the stream. */
467   if (s->cbs_hd)
468     {
469       if (s->cbs.release)
470         rc = s->cbs.release (s->cbs_hd);
471       else
472         rc = 0;
473       cdk_free (s);
474       gnutls_assert ();
475       return rc;
476     }
477
478
479   rc = 0;
480   if (!s->flags.filtrated && !s->error)
481     rc = cdk_stream_flush (s);
482   if (!s->fp_ref && (s->fname || s->flags.temp))
483     {
484       int err;
485
486       _gnutls_read_log ("close stream fd=%d\n", fileno (s->fp));
487       err = fclose (s->fp);
488       s->fp = NULL;
489       if (err)
490         rc = CDK_File_Error;
491     }
492
493   /* Iterate over the filter list and use the cleanup flag to
494      free the allocated internal structures. */
495   f = s->filters;
496   while (f)
497     {
498       f2 = f->next;
499       if (f->fnct)
500         f->fnct (f->opaque, STREAMCTL_FREE, NULL, NULL);
501       cdk_free (f);
502       f = f2;
503     }
504
505   if (s->fname)
506     {
507       cdk_free (s->fname);
508       s->fname = NULL;
509     }
510
511   cdk_free (s->cache.buf);
512   s->cache.alloced = 0;
513
514   cdk_free (s);
515   gnutls_assert ();
516   return rc;
517 }
518
519
520 /**
521  * cdk_stream_eof:
522  * @s: The STREAM object.
523  *
524  *  Return if the associated file handle was set to EOF.  This
525  *  function will only work with read streams.
526  **/
527 int
528 cdk_stream_eof (cdk_stream_t s)
529 {
530   return s ? s->flags.eof : -1;
531 }
532
533
534 const char *
535 _cdk_stream_get_fname (cdk_stream_t s)
536 {
537   if (!s)
538     return NULL;
539   if (s->flags.temp)
540     return NULL;
541   return s->fname ? s->fname : NULL;
542 }
543
544
545 /* Return the underlying FP of the stream.
546    WARNING: This handle should not be closed. */
547 FILE *
548 _cdk_stream_get_fp (cdk_stream_t s)
549 {
550   return s ? s->fp : NULL;
551 }
552
553
554 int
555 _cdk_stream_get_errno (cdk_stream_t s)
556 {
557   return s ? s->error : CDK_Inv_Value;
558 }
559
560
561 /**
562  * cdk_stream_get_length:
563  * @s: The STREAM object.
564  *
565  * Return the length of the associated file handle.  This function
566  * should work for both read and write streams. For write streams an
567  * additional flush is used to write possible pending data.
568  **/
569 off_t
570 cdk_stream_get_length (cdk_stream_t s)
571 {
572   struct stat statbuf;
573   cdk_error_t rc;
574
575   if (!s)
576     {
577       gnutls_assert ();
578       return (off_t) - 1;
579     }
580
581   /* The user callback does not support stat. */
582   if (s->cbs_hd)
583     return 0;
584
585   rc = stream_flush (s);
586   if (rc)
587     {
588       s->error = rc;
589       gnutls_assert ();
590       return (off_t) - 1;
591     }
592
593   if (fstat (fileno (s->fp), &statbuf))
594     {
595       s->error = CDK_File_Error;
596       gnutls_assert ();
597       return (off_t) - 1;
598     }
599
600   return statbuf.st_size;
601 }
602
603
604 static struct stream_filter_s *
605 filter_add2 (cdk_stream_t s)
606 {
607   struct stream_filter_s *f;
608
609   assert (s);
610
611   f = cdk_calloc (1, sizeof *f);
612   if (!f)
613     return NULL;
614   f->next = s->filters;
615   s->filters = f;
616   return f;
617 }
618
619
620 static struct stream_filter_s *
621 filter_search (cdk_stream_t s, filter_fnct_t fnc)
622 {
623   struct stream_filter_s *f;
624
625   assert (s);
626
627   for (f = s->filters; f; f = f->next)
628     {
629       if (f->fnct == fnc)
630         return f;
631     }
632
633   return NULL;
634 }
635
636 static inline void
637 set_opaque (struct stream_filter_s *f)
638 {
639   switch (f->type)
640     {
641     case fARMOR:
642       f->opaque = &f->u.afx;
643       break;
644     case fCIPHER:
645       f->opaque = &f->u.cfx;
646       break;
647     case fLITERAL:
648       f->opaque = &f->u.pfx;
649       break;
650     case fCOMPRESS:
651       f->opaque = &f->u.zfx;
652       break;
653     case fHASH:
654       f->opaque = &f->u.mfx;
655       break;
656     case fTEXT:
657       f->opaque = &f->u.tfx;
658       break;
659     default:
660       f->opaque = NULL;
661     }
662
663 }
664
665 struct stream_filter_s *
666 filter_add (cdk_stream_t s, filter_fnct_t fnc, int type)
667 {
668   struct stream_filter_s *f;
669
670   assert (s);
671
672   s->flags.filtrated = 0;
673   f = filter_search (s, fnc);
674   if (f)
675     return f;
676   f = filter_add2 (s);
677   if (!f)
678     return NULL;
679   f->fnct = fnc;
680   f->flags.enabled = 1;
681   f->tmp = NULL;
682   f->type = type;
683
684   set_opaque (f);
685
686   return f;
687 }
688
689 static int
690 stream_get_mode (cdk_stream_t s)
691 {
692   assert (s);
693
694   if (s->flags.temp)
695     return s->fmode;
696   return s->flags.write;
697 }
698
699
700 static filter_fnct_t
701 stream_id_to_filter (int type)
702 {
703   switch (type)
704     {
705     case fARMOR:
706       return _cdk_filter_armor;
707     case fLITERAL:
708       return _cdk_filter_literal;
709     case fTEXT:
710       return _cdk_filter_text;
711 /*    case fCIPHER  : return _cdk_filter_cipher; */
712 /*    case fCOMPRESS: return _cdk_filter_compress; */
713     default:
714       return NULL;
715     }
716 }
717
718
719 /**
720  * cdk_stream_filter_disable: 
721  * @s: The STREAM object
722  * @type: The numberic filter ID.
723  *
724  * Disables the filter with the type 'type'.
725  **/
726 cdk_error_t
727 cdk_stream_filter_disable (cdk_stream_t s, int type)
728 {
729   struct stream_filter_s *f;
730   filter_fnct_t fnc;
731
732   if (!s)
733     {
734       gnutls_assert ();
735       return CDK_Inv_Value;
736     }
737
738   fnc = stream_id_to_filter (type);
739   if (!fnc)
740     {
741       gnutls_assert ();
742       return CDK_Inv_Value;
743     }
744   f = filter_search (s, fnc);
745   if (f)
746     f->flags.enabled = 0;
747   return 0;
748 }
749
750
751 /* WARNING: tmp should not be closed by the caller. */
752 static cdk_error_t
753 stream_fp_replace (cdk_stream_t s, FILE ** tmp)
754 {
755   int rc;
756
757   assert (s);
758
759   _gnutls_read_log ("replace stream fd=%d with fd=%d\n",
760                     fileno (s->fp), fileno (*tmp));
761   rc = fclose (s->fp);
762   if (rc)
763     {
764       s->fp = NULL;
765       gnutls_assert ();
766       return CDK_File_Error;
767     }
768   s->fp = *tmp;
769   *tmp = NULL;
770   return 0;
771 }
772
773
774 /* This function is exactly like filter_read, except the fact that we can't
775    use tmpfile () all the time. That's why we open the real file when there
776    is no last filter. */
777 static cdk_error_t
778 stream_filter_write (cdk_stream_t s)
779 {
780   struct stream_filter_s *f;
781   cdk_error_t rc = 0;
782
783   assert (s);
784
785   if (s->flags.filtrated)
786     {
787       gnutls_assert ();
788       return CDK_Inv_Value;
789     }
790
791   for (f = s->filters; f; f = f->next)
792     {
793       if (!f->flags.enabled)
794         continue;
795       /* if there is no next filter, create the final output file */
796       _gnutls_read_log ("filter [write]: last filter=%d fname=%s\n",
797                         f->next ? 1 : 0, s->fname);
798       if (!f->next && s->fname)
799         f->tmp = fopen (s->fname, "w+b");
800       else
801         f->tmp = _cdk_tmpfile ();
802       if (!f->tmp)
803         {
804           rc = CDK_File_Error;
805           break;
806         }
807       /* If there is no next filter, flush the cache. We also do this
808          when the next filter is the armor filter because this filter
809          is special and before it starts, all data should be written. */
810       if ((!f->next || f->next->type == fARMOR) && s->cache.size)
811         {
812           rc = stream_cache_flush (s, f->tmp);
813           if (rc)
814             break;
815         }
816       rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
817       _gnutls_read_log ("filter [write]: type=%d rc=%d\n", f->type, rc);
818       if (!rc)
819         rc = stream_fp_replace (s, &f->tmp);
820       if (!rc)
821         rc = cdk_stream_seek (s, 0);
822       if (rc)
823         {
824           _gnutls_read_log ("filter [close]: fd=%d\n", fileno (f->tmp));
825           fclose (f->tmp);
826           f->tmp = NULL;
827           break;
828         }
829     }
830   return rc;
831 }
832
833
834 /* Here all data from the file handle is passed through all filters.
835    The scheme works like this:
836    Create a tempfile and use it for the output of the filter. Then the
837    original file handle will be closed and replace with the temp handle.
838    The file pointer will be set to the begin and the game starts again. */
839 static cdk_error_t
840 stream_filter_read (cdk_stream_t s)
841 {
842   struct stream_filter_s *f;
843   cdk_error_t rc = 0;
844
845   assert (s);
846
847   if (s->flags.filtrated)
848     return 0;
849
850   for (f = s->filters; f; f = f->next)
851     {
852       if (!f->flags.enabled)
853         continue;
854       if (f->flags.error)
855         {
856           _gnutls_read_log ("filter %s [read]: has the error flag; skipped\n",
857                             s->fname ? s->fname : "[temp]");
858           continue;
859         }
860
861       f->tmp = _cdk_tmpfile ();
862       if (!f->tmp)
863         {
864           rc = CDK_File_Error;
865           break;
866         }
867       rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
868       _gnutls_read_log ("filter %s [read]: type=%d rc=%d\n",
869                         s->fname ? s->fname : "[temp]", f->type, rc);
870       if (rc)
871         {
872           f->flags.error = 1;
873           break;
874         }
875
876       f->flags.error = 0;
877       /* If the filter is read-only, do not replace the FP because
878          the contents were not altered in any way. */
879       if (!f->flags.rdonly)
880         {
881           rc = stream_fp_replace (s, &f->tmp);
882           if (rc)
883             break;
884         }
885       else
886         {
887           fclose (f->tmp);
888           f->tmp = NULL;
889         }
890       rc = cdk_stream_seek (s, 0);
891       if (rc)
892         break;
893       /* Disable the filter after it was successfully used. The idea
894          is the following: let's say the armor filter was pushed and
895          later more filters were added. The second time the filter code
896          will be executed, only the new filter should be started but
897          not the old because we already used it. */
898       f->flags.enabled = 0;
899     }
900
901   return rc;
902 }
903
904
905 void *
906 _cdk_stream_get_opaque (cdk_stream_t s, int fid)
907 {
908   struct stream_filter_s *f;
909
910   if (!s)
911     return NULL;
912
913   for (f = s->filters; f; f = f->next)
914     {
915       if ((int) f->type == fid)
916         return f->opaque;
917     }
918   return NULL;
919 }
920
921
922 /**
923  * cdk_stream_read: 
924  * @s: The STREAM object.
925  * @buf: The buffer to insert the readed bytes.
926  * @count: Request so much bytes.
927  *
928  * Tries to read count bytes from the STREAM object.
929  * When this function is called the first time, it can take a while
930  * because all filters need to be processed. Please remember that you
931  * need to add the filters in reserved order.
932  **/
933 int
934 cdk_stream_read (cdk_stream_t s, void *buf, size_t buflen)
935 {
936   int nread;
937   int rc;
938
939   if (!s)
940     {
941       gnutls_assert ();
942       return EOF;
943     }
944
945   if (s->cbs_hd)
946     {
947       if (s->cbs.read)
948         return s->cbs.read (s->cbs_hd, buf, buflen);
949       return 0;
950     }
951
952   if (s->flags.write && !s->flags.temp)
953     {
954       s->error = CDK_Inv_Mode;
955       gnutls_assert ();
956       return EOF;               /* This is a write stream */
957     }
958
959   if (!s->flags.no_filter && !s->cache.on && !s->flags.filtrated)
960     {
961       rc = stream_filter_read (s);
962       if (rc)
963         {
964           s->error = rc;
965           if (s->fp && feof (s->fp))
966             s->flags.eof = 1;
967           gnutls_assert ();
968           return EOF;
969         }
970       s->flags.filtrated = 1;
971     }
972
973   if (!buf && !buflen)
974     return 0;
975
976   nread = fread (buf, 1, buflen, s->fp);
977   if (!nread)
978     nread = EOF;
979
980   if (feof (s->fp))
981     {
982       s->error = 0;
983       s->flags.eof = 1;
984     }
985   return nread;
986 }
987
988
989 int
990 cdk_stream_getc (cdk_stream_t s)
991 {
992   unsigned char buf[2];
993   int nread;
994
995   if (!s)
996     {
997       gnutls_assert ();
998       return EOF;
999     }
1000   nread = cdk_stream_read (s, buf, 1);
1001   if (nread == EOF)
1002     {
1003       s->error = CDK_File_Error;
1004       gnutls_assert ();
1005       return EOF;
1006     }
1007   return buf[0];
1008 }
1009
1010
1011 /**
1012  * cdk_stream_write: 
1013  * @s: The STREAM object
1014  * @buf: The buffer with the values to write.
1015  * @count: The size of the buffer.
1016  *
1017  * Tries to write count bytes into the stream.
1018  * In this function we simply write the bytes to the stream. We can't
1019  * use the filters here because it would mean they have to support
1020  * partial flushing.
1021  **/
1022 int
1023 cdk_stream_write (cdk_stream_t s, const void *buf, size_t count)
1024 {
1025   int nwritten;
1026
1027   if (!s)
1028     {
1029       gnutls_assert ();
1030       return EOF;
1031     }
1032
1033   if (s->cbs_hd)
1034     {
1035       if (s->cbs.write)
1036         return s->cbs.write (s->cbs_hd, buf, count);
1037       return 0;
1038     }
1039
1040   if (!s->flags.write)
1041     {
1042       s->error = CDK_Inv_Mode;  /* this is a read stream */
1043       gnutls_assert ();
1044       return EOF;
1045     }
1046
1047   if (!buf && !count)
1048     return stream_flush (s);
1049
1050   if (s->cache.on)
1051     {
1052       /* We need to resize the buffer if the additional data wouldn't
1053          fit into it. We allocate more memory to avoid to resize it the
1054          next time the function is used. */
1055       if (s->cache.size + count > s->cache.alloced)
1056         {
1057           byte *old = s->cache.buf;
1058
1059           s->cache.buf =
1060             cdk_calloc (1, s->cache.alloced + count + STREAM_BUFSIZE);
1061           s->cache.alloced += (count + STREAM_BUFSIZE);
1062           memcpy (s->cache.buf, old, s->cache.size);
1063           cdk_free (old);
1064           _gnutls_read_log ("stream: enlarge cache to %d octets\n",
1065                             (int) s->cache.alloced);
1066         }
1067       memcpy (s->cache.buf + s->cache.size, buf, count);
1068       s->cache.size += count;
1069       return count;
1070     }
1071
1072   nwritten = fwrite (buf, 1, count, s->fp);
1073   if (!nwritten)
1074     nwritten = EOF;
1075   return nwritten;
1076 }
1077
1078
1079 int
1080 cdk_stream_putc (cdk_stream_t s, int c)
1081 {
1082   byte buf[2];
1083   int nwritten;
1084
1085   if (!s)
1086     {
1087       gnutls_assert ();
1088       return EOF;
1089     }
1090   buf[0] = c;
1091   nwritten = cdk_stream_write (s, buf, 1);
1092   if (nwritten == EOF)
1093     return EOF;
1094   return 0;
1095 }
1096
1097
1098 off_t
1099 cdk_stream_tell (cdk_stream_t s)
1100 {
1101   return s ? ftell (s->fp) : (off_t) - 1;
1102 }
1103
1104
1105 cdk_error_t
1106 cdk_stream_seek (cdk_stream_t s, off_t offset)
1107 {
1108   off_t len;
1109
1110   if (!s)
1111     {
1112       gnutls_assert ();
1113       return CDK_Inv_Value;
1114     }
1115
1116   if (s->cbs_hd)
1117     {
1118       if (s->cbs.seek)
1119         return s->cbs.seek (s->cbs_hd, offset);
1120       return 0;
1121     }
1122
1123   /* Set or reset the EOF flag. */
1124   len = cdk_stream_get_length (s);
1125   if (len == offset)
1126     s->flags.eof = 1;
1127   else
1128     s->flags.eof = 0;
1129
1130   if (fseek (s->fp, offset, SEEK_SET))
1131     {
1132       gnutls_assert ();
1133       return CDK_File_Error;
1134     }
1135   return 0;
1136 }
1137
1138
1139 static cdk_error_t
1140 stream_flush (cdk_stream_t s)
1141 {
1142   assert (s);
1143
1144   /* For some constellations it cannot be assured that the
1145      return value is defined, thus we ignore it for now. */
1146   (void) fflush (s->fp);
1147   return 0;
1148 }
1149
1150
1151 /**
1152  * cdk_stream_set_armor_flag:
1153  * @s: the stream object
1154  * @type: the type of armor to use
1155  * 
1156  * If the file is in read-mode, no armor type needs to be
1157  * defined (armor_type=0) because the armor filter will be
1158  * used for decoding existing armor data.
1159  * For the write mode, @armor_type can be set to any valid
1160  * armor type (message, key, sig).
1161  **/
1162 cdk_error_t
1163 cdk_stream_set_armor_flag (cdk_stream_t s, int armor_type)
1164 {
1165   struct stream_filter_s *f;
1166
1167   if (!s)
1168     {
1169       gnutls_assert ();
1170       return CDK_Inv_Value;
1171     }
1172   f = filter_add (s, _cdk_filter_armor, fARMOR);
1173   if (!f)
1174     {
1175       gnutls_assert ();
1176       return CDK_Out_Of_Core;
1177     }
1178   f->u.afx.idx = f->u.afx.idx2 = armor_type;
1179   f->ctl = stream_get_mode (s);
1180   return 0;
1181 }
1182
1183
1184 /**
1185  * cdk_stream_set_literal_flag:
1186  * @s: the stream object
1187  * @mode: the mode to use (binary, text, unicode)
1188  * @fname: the file name to store in the packet.
1189  *
1190  * In read mode it kicks off the literal decoding routine to
1191  * unwrap the data from the packet. The @mode parameter is ignored.
1192  * In write mode the function can be used to wrap the stream data
1193  * into a literal packet with the given mode and file name.
1194  **/
1195 cdk_error_t
1196 cdk_stream_set_literal_flag (cdk_stream_t s, cdk_lit_format_t mode,
1197                              const char *fname)
1198 {
1199   struct stream_filter_s *f;
1200   const char *orig_fname;
1201
1202   _gnutls_read_log ("stream: enable literal mode.\n");
1203
1204   if (!s)
1205     {
1206       gnutls_assert ();
1207       return CDK_Inv_Value;
1208     }
1209
1210   orig_fname = _cdk_stream_get_fname (s);
1211   f = filter_add (s, _cdk_filter_literal, fLITERAL);
1212   if (!f)
1213     {
1214       gnutls_assert ();
1215       return CDK_Out_Of_Core;
1216     }
1217   f->u.pfx.mode = mode;
1218   f->u.pfx.filename = fname ? cdk_strdup (fname) : NULL;
1219   f->u.pfx.orig_filename = orig_fname ? cdk_strdup (orig_fname) : NULL;
1220   f->ctl = stream_get_mode (s);
1221   if (s->blkmode > 0)
1222     {
1223       f->u.pfx.blkmode.on = 1;
1224       f->u.pfx.blkmode.size = s->blkmode;
1225     }
1226   return 0;
1227 }
1228
1229
1230 /**
1231  * cdk_stream_set_compress_flag:
1232  * @s: the stream object
1233  * @algo: the compression algo
1234  * @level: level of compression (0..9)
1235  * 
1236  * In read mode it kicks off the decompression filter to retrieve
1237  * the uncompressed data.
1238  * In write mode the stream data will be compressed with the
1239  * given algorithm at the given level.
1240  **/
1241 cdk_error_t
1242 cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level)
1243 {
1244
1245   gnutls_assert ();
1246   return CDK_Not_Implemented;
1247
1248 #if 0
1249   struct stream_filter_s *f;
1250
1251   if (!s)
1252     return CDK_Inv_Value;
1253   f = filter_add (s, _cdk_filter_compress, fCOMPRESS);
1254   if (!f)
1255     return CDK_Out_Of_Core;
1256   f->ctl = stream_get_mode (s);
1257   f->u.zfx.algo = algo;
1258   f->u.zfx.level = level;
1259   return 0;
1260 #endif
1261 }
1262
1263
1264 /**
1265  * cdk_stream_set_text_flag:
1266  * @s: the stream object
1267  * @lf: line ending
1268  * 
1269  * Pushes the text filter to store the stream data in cannoncial format.
1270  **/
1271 cdk_error_t
1272 cdk_stream_set_text_flag (cdk_stream_t s, const char *lf)
1273 {
1274   struct stream_filter_s *f;
1275
1276   if (!s)
1277     {
1278       gnutls_assert ();
1279       return CDK_Inv_Value;
1280     }
1281   f = filter_add (s, _cdk_filter_text, fTEXT);
1282   if (!f)
1283     {
1284       gnutls_assert ();
1285       return CDK_Out_Of_Core;
1286     }
1287   f->ctl = stream_get_mode (s);
1288   f->u.tfx.lf = lf;
1289   return 0;
1290 }
1291
1292
1293 /**
1294  * cdk_stream_set_hash_flag:
1295  * @s: the stream object
1296  * @digest_algo: the digest algorithm to use
1297  * 
1298  * This is for read-only streams. It pushes a digest filter to
1299  * calculate the digest of the given stream data.
1300  **/
1301 cdk_error_t
1302 cdk_stream_set_hash_flag (cdk_stream_t s, int digest_algo)
1303 {
1304   struct stream_filter_s *f;
1305
1306   if (!s)
1307     {
1308       gnutls_assert ();
1309       return CDK_Inv_Value;
1310     }
1311   if (stream_get_mode (s))
1312     {
1313       gnutls_assert ();
1314       return CDK_Inv_Mode;
1315     }
1316   f = filter_add (s, _cdk_filter_hash, fHASH);
1317   if (!f)
1318     {
1319       gnutls_assert ();
1320       return CDK_Out_Of_Core;
1321     }
1322   f->ctl = stream_get_mode (s);
1323   f->u.mfx.digest_algo = digest_algo;
1324   f->flags.rdonly = 1;
1325   return 0;
1326 }
1327
1328
1329 /**
1330  * cdk_stream_enable_cache:
1331  * @s: the stream object
1332  * @val: 1=on, 0=off
1333  *
1334  * Enables or disable the cache section of a stream object.
1335  **/
1336 cdk_error_t
1337 cdk_stream_enable_cache (cdk_stream_t s, int val)
1338 {
1339   if (!s)
1340     {
1341       gnutls_assert ();
1342       return CDK_Inv_Value;
1343     }
1344   if (!s->flags.write)
1345     {
1346       gnutls_assert ();
1347       return CDK_Inv_Mode;
1348     }
1349   s->cache.on = val;
1350   if (!s->cache.buf)
1351     {
1352       s->cache.buf = cdk_calloc (1, STREAM_BUFSIZE);
1353       s->cache.alloced = STREAM_BUFSIZE;
1354       _gnutls_read_log ("stream: allocate cache of %d octets\n",
1355                         STREAM_BUFSIZE);
1356     }
1357   return 0;
1358 }
1359
1360
1361 static int
1362 stream_cache_flush (cdk_stream_t s, FILE * fp)
1363 {
1364   int nwritten;
1365
1366   assert (s);
1367
1368   /* FIXME: We should find a way to use cdk_stream_write here. */
1369   if (s->cache.size > 0)
1370     {
1371       nwritten = fwrite (s->cache.buf, 1, s->cache.size, fp);
1372       if (!nwritten)
1373         {
1374           gnutls_assert ();
1375           return CDK_File_Error;
1376         }
1377       s->cache.size = 0;
1378       s->cache.on = 0;
1379       wipemem (s->cache.buf, s->cache.alloced);
1380     }
1381   return 0;
1382 }
1383
1384
1385 /**
1386  * cdk_stream_kick_off:
1387  * @inp: the input stream
1388  * @out: the output stream.
1389  * 
1390  * Passes the entire data from @inp into the output stream @out
1391  * with all the activated filters.
1392  */
1393 cdk_error_t
1394 cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out)
1395 {
1396   byte buf[BUFSIZE];
1397   int nread, nwritten;
1398   cdk_error_t rc;
1399
1400   if (!inp || !out)
1401     {
1402       gnutls_assert ();
1403       return CDK_Inv_Value;
1404     }
1405   rc = CDK_Success;
1406   while (!cdk_stream_eof (inp))
1407     {
1408       nread = cdk_stream_read (inp, buf, DIM (buf));
1409       if (!nread || nread == EOF)
1410         break;
1411       nwritten = cdk_stream_write (out, buf, nread);
1412       if (!nwritten || nwritten == EOF)
1413         {                       /* In case of errors, we leave the loop. */
1414           rc = inp->error;
1415           break;
1416         }
1417     }
1418
1419   wipemem (buf, sizeof (buf));
1420   return rc;
1421 }
1422
1423
1424 /**
1425  * cdk_stream_mmap_part:
1426  * @s: the stream
1427  * @off: the offset where to start
1428  * @len: how much bytes shall be mapped
1429  * @ret_buf: the buffer to store the content
1430  * @ret_buflen: length of the buffer
1431  *
1432  * Maps the data of the given stream into a memory section. @ret_count
1433  * contains the length of the buffer.
1434  **/
1435 cdk_error_t
1436 cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
1437                       byte ** ret_buf, size_t * ret_buflen)
1438 {
1439   cdk_error_t rc;
1440   off_t oldpos;
1441   unsigned int n;
1442
1443   if (!ret_buf || !ret_buflen)
1444     {
1445       gnutls_assert ();
1446       return CDK_Inv_Value;
1447     }
1448   *ret_buf = NULL;
1449   *ret_buflen = 0;
1450
1451   if (!s)
1452     {
1453       gnutls_assert ();
1454       return CDK_Inv_Value;
1455     }
1456
1457   /* Memory mapping is not supported on custom I/O objects. */
1458   if (s->cbs_hd)
1459     {
1460       _gnutls_read_log ("cdk_stream_mmap_part: not supported on callbacks\n");
1461       gnutls_assert ();
1462       return CDK_Inv_Mode;
1463     }
1464
1465   oldpos = cdk_stream_tell (s);
1466   rc = cdk_stream_flush (s);
1467   if (rc)
1468     {
1469       gnutls_assert ();
1470       return rc;
1471     }
1472   rc = cdk_stream_seek (s, off);
1473   if (rc)
1474     {
1475       gnutls_assert ();
1476       return rc;
1477     }
1478   if (!len)
1479     len = cdk_stream_get_length (s);
1480   if (!len)
1481     {
1482       _gnutls_read_log ("cdk_stream_mmap_part: invalid file size %lu\n", len);
1483       gnutls_assert ();
1484       return s->error;
1485     }
1486   if (len > MAX_MAP_SIZE)
1487     {
1488       gnutls_assert ();
1489       return CDK_Too_Short;
1490     }
1491
1492   *ret_buf = cdk_calloc (1, len + 1);
1493   *ret_buflen = len;
1494   n = cdk_stream_read (s, *ret_buf, len);
1495   if (n != len)
1496     *ret_buflen = n;
1497   rc = cdk_stream_seek (s, oldpos);
1498   if (rc)
1499     gnutls_assert ();
1500   return rc;
1501 }
1502
1503
1504 cdk_error_t
1505 cdk_stream_mmap (cdk_stream_t inp, byte ** buf, size_t * buflen)
1506 {
1507   off_t len;
1508
1509   /* We need to make sure all data is flushed before we retrieve the size. */
1510   cdk_stream_flush (inp);
1511   len = cdk_stream_get_length (inp);
1512   return cdk_stream_mmap_part (inp, 0, len, buf, buflen);
1513 }
1514
1515
1516 /**
1517  * cdk_stream_peek:
1518  * @inp: the input stream handle
1519  * @s: buffer
1520  * @count: number of bytes to peek
1521  *
1522  * The function acts like cdk_stream_read with the difference that
1523  * the file pointer is moved to the old position after the bytes were read.
1524  **/
1525 int
1526 cdk_stream_peek (cdk_stream_t inp, byte * buf, size_t buflen)
1527 {
1528   off_t off;
1529   int nbytes;
1530
1531   if (!inp || !buf)
1532     return 0;
1533   if (inp->cbs_hd)
1534     return 0;
1535
1536   off = cdk_stream_tell (inp);
1537   nbytes = cdk_stream_read (inp, buf, buflen);
1538   if (nbytes == -1)
1539     return 0;
1540   if (cdk_stream_seek (inp, off))
1541     return 0;
1542   return nbytes;
1543 }
1544
1545
1546 /* Try to read a line from the given stream. */
1547 int
1548 _cdk_stream_gets (cdk_stream_t s, char *buf, size_t count)
1549 {
1550   int c, i;
1551
1552   assert (s);
1553
1554   i = 0;
1555   while (!cdk_stream_eof (s) && count > 0)
1556     {
1557       c = cdk_stream_getc (s);
1558       if (c == EOF || c == '\r' || c == '\n')
1559         {
1560           buf[i++] = '\0';
1561           break;
1562         }
1563       buf[i++] = c;
1564       count--;
1565     }
1566   return i;
1567 }
1568
1569
1570 /* Try to write string into the stream @s. */
1571 int
1572 _cdk_stream_puts (cdk_stream_t s, const char *buf)
1573 {
1574   return cdk_stream_write (s, buf, strlen (buf));
1575 }
1576
1577
1578 /* Activate the block mode for the given stream. */
1579 cdk_error_t
1580 _cdk_stream_set_blockmode (cdk_stream_t s, size_t nbytes)
1581 {
1582   assert (s);
1583
1584   _gnutls_read_log ("stream: activate block mode with blocksize %d\n",
1585                     (int) nbytes);
1586   s->blkmode = nbytes;
1587   return 0;
1588 }
1589
1590
1591 /* Return the block mode state of the given stream. */
1592 int
1593 _cdk_stream_get_blockmode (cdk_stream_t s)
1594 {
1595   return s ? s->blkmode : 0;
1596 }