check for either iconv or libiconv.
[gnutls.git] / lib / opencdk / stream.c
blobaff110978d87cae49ec9ad4c5a11d2f01437e96a
1 /* stream.c - The stream implementation
2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4 * Author: Timo Schulz
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <assert.h>
27 #include <stdio.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
36 #include "opencdk.h"
37 #include "main.h"
38 #include "filters.h"
39 #include "stream.h"
40 #include "types.h"
42 /* This is the maximal amount of bytes we map. */
43 #define MAX_MAP_SIZE 16777216
45 static cdk_error_t stream_flush (cdk_stream_t s);
46 static cdk_error_t stream_filter_write (cdk_stream_t s);
47 static int stream_cache_flush (cdk_stream_t s, FILE * fp);
48 struct stream_filter_s *filter_add (cdk_stream_t s, filter_fnct_t fnc,
49 int type);
52 /* FIXME: The read/write/putc/getc function cannot directly
53 return an error code. It is stored in an error variable
54 inside the string. Right now there is no code to
55 return the error code or to reset it. */
57 /**
58 * cdk_stream_open:
59 * @file: The file to open
60 * @ret_s: The new STREAM object
62 * Creates a new stream based on an existing file. The stream is
63 * opened in read-only mode.
64 **/
65 cdk_error_t
66 cdk_stream_open (const char *file, cdk_stream_t * ret_s)
68 return _cdk_stream_open_mode (file, "rb", ret_s);
72 /* Helper function to allow to open a stream in different modes. */
73 cdk_error_t
74 _cdk_stream_open_mode (const char *file, const char *mode,
75 cdk_stream_t * ret_s)
77 cdk_stream_t s;
79 if (!file || !ret_s)
81 gnutls_assert ();
82 return CDK_Inv_Value;
85 #ifdef DEBUG_STREAM
86 _gnutls_read_log ("open stream `%s'\n", file);
87 #endif
88 *ret_s = NULL;
89 s = cdk_calloc (1, sizeof *s);
90 if (!s)
92 gnutls_assert ();
93 return CDK_Out_Of_Core;
95 s->fname = cdk_strdup (file);
96 if (!s->fname)
98 cdk_free (s);
99 gnutls_assert ();
100 return CDK_Out_Of_Core;
102 s->fp = fopen (file, mode);
103 if (!s->fp)
105 cdk_free (s->fname);
106 cdk_free (s);
107 gnutls_assert ();
108 return CDK_File_Error;
110 #ifdef DEBUG_STREAM
111 _gnutls_read_log ("open stream fd=%d\n", fileno (s->fp));
112 #endif
113 s->flags.write = 0;
114 *ret_s = s;
115 return 0;
120 * cdk_stream_new_from_cbs:
121 * @cbs: the callback context with all user callback functions
122 * @opa: uint8_t handle which is passed to all callbacks.
123 * @ret_s: the allocated stream
125 * This function creates a stream which uses user callback
126 * for the core operations (open, close, read, write, seek).
128 cdk_error_t
129 cdk_stream_new_from_cbs (cdk_stream_cbs_t cbs, void *opa,
130 cdk_stream_t * ret_s)
132 cdk_stream_t s;
134 if (!cbs || !opa || !ret_s)
136 gnutls_assert ();
137 return CDK_Inv_Value;
140 *ret_s = NULL;
141 s = cdk_calloc (1, sizeof *s);
142 if (!s)
144 gnutls_assert ();
145 return CDK_Out_Of_Core;
148 s->cbs.read = cbs->read;
149 s->cbs.write = cbs->write;
150 s->cbs.seek = cbs->seek;
151 s->cbs.release = cbs->release;
152 s->cbs.open = cbs->open;
153 s->cbs_hd = opa;
154 *ret_s = s;
156 /* If there is a user callback for open, we need to call it
157 here because read/write expects an open stream. */
158 if (s->cbs.open)
159 return s->cbs.open (s->cbs_hd);
160 return 0;
165 * cdk_stream_new:
166 * @file: The name of the new file
167 * @ret_s: The new STREAM object
169 * Create a new stream into the given file.
171 cdk_error_t
172 cdk_stream_new (const char *file, cdk_stream_t * ret_s)
174 cdk_stream_t s;
176 if (!ret_s)
178 gnutls_assert ();
179 return CDK_Inv_Value;
182 #ifdef DEBUG_STREAM
183 _gnutls_read_log ("new stream `%s'\n", file ? file : "[temp]");
184 #endif
185 *ret_s = NULL;
186 s = cdk_calloc (1, sizeof *s);
187 if (!s)
189 gnutls_assert ();
190 return CDK_Out_Of_Core;
192 s->flags.write = 1;
193 if (!file)
194 s->flags.temp = 1;
195 else
197 s->fname = cdk_strdup (file);
198 if (!s->fname)
200 cdk_free (s);
201 gnutls_assert ();
202 return CDK_Out_Of_Core;
205 s->fp = _cdk_tmpfile ();
206 if (!s->fp)
208 cdk_free (s->fname);
209 cdk_free (s);
210 gnutls_assert ();
211 return CDK_File_Error;
213 #ifdef DEBUG_STREAM
214 _gnutls_read_log ("new stream fd=%d\n", fileno (s->fp));
215 #endif
216 *ret_s = s;
217 return 0;
221 * cdk_stream_create:
222 * @file: the filename
223 * @ret_s: the object
225 * Creates a new stream.
226 * The difference to cdk_stream_new is, that no filtering can be used with
227 * this kind of stream and everything is written directly to the stream.
229 cdk_error_t
230 cdk_stream_create (const char *file, cdk_stream_t * ret_s)
232 cdk_stream_t s;
234 if (!file || !ret_s)
236 gnutls_assert ();
237 return CDK_Inv_Value;
240 #ifdef DEBUG_STREAM
241 _gnutls_read_log ("create stream `%s'\n", file);
242 #endif
243 *ret_s = NULL;
244 s = cdk_calloc (1, sizeof *s);
245 if (!s)
247 gnutls_assert ();
248 return CDK_Out_Of_Core;
250 s->flags.write = 1;
251 s->flags.filtrated = 1;
252 s->fname = cdk_strdup (file);
253 if (!s->fname)
255 cdk_free (s);
256 gnutls_assert ();
257 return CDK_Out_Of_Core;
259 s->fp = fopen (file, "w+b");
260 if (!s->fp)
262 cdk_free (s->fname);
263 cdk_free (s);
264 gnutls_assert ();
265 return CDK_File_Error;
267 #ifdef DEBUG_STREAM
268 _gnutls_read_log ("stream create fd=%d\n", fileno (s->fp));
269 #endif
270 *ret_s = s;
271 return 0;
276 * cdk_stream_tmp_new:
277 * @r_out: the new temp stream.
279 * Allocates a new tempory stream which is not associated with a file.
281 cdk_error_t
282 cdk_stream_tmp_new (cdk_stream_t * r_out)
284 return cdk_stream_new (NULL, r_out);
290 * cdk_stream_tmp_from_mem:
291 * @buf: the buffer which shall be written to the temp stream.
292 * @buflen: how large the buffer is
293 * @r_out: the new stream with the given contents.
295 * Creates a new tempory stream with the given contests.
297 cdk_error_t
298 cdk_stream_tmp_from_mem (const void *buf, size_t buflen, cdk_stream_t * r_out)
300 cdk_stream_t s;
301 cdk_error_t rc;
302 int nwritten;
304 *r_out = NULL;
305 rc = cdk_stream_tmp_new (&s);
306 if (rc)
308 gnutls_assert ();
309 return rc;
312 nwritten = cdk_stream_write (s, buf, buflen);
313 if (nwritten == EOF)
315 cdk_stream_close (s);
316 gnutls_assert ();
317 return s->error;
319 cdk_stream_seek (s, 0);
320 *r_out = s;
321 return 0;
325 cdk_error_t
326 _cdk_stream_fpopen (FILE * fp, unsigned write_mode, cdk_stream_t * ret_out)
328 cdk_stream_t s;
330 *ret_out = NULL;
331 s = cdk_calloc (1, sizeof *s);
332 if (!s)
334 gnutls_assert ();
335 return CDK_Out_Of_Core;
338 #ifdef DEBUG_STREAM
339 _gnutls_read_log ("stream ref fd=%d\n", fileno (fp));
340 #endif
341 s->fp = fp;
342 s->fp_ref = 1;
343 s->flags.filtrated = 1;
344 s->flags.write = write_mode;
346 *ret_out = s;
347 return 0;
351 cdk_error_t
352 _cdk_stream_append (const char *file, cdk_stream_t * ret_s)
354 cdk_stream_t s;
355 cdk_error_t rc;
357 if (!ret_s)
359 gnutls_assert ();
360 return CDK_Inv_Value;
362 *ret_s = NULL;
364 rc = _cdk_stream_open_mode (file, "a+b", &s);
365 if (rc)
367 gnutls_assert ();
368 return rc;
371 /* In the append mode, we need to write to the flag. */
372 s->flags.write = 1;
373 *ret_s = s;
374 return 0;
378 * cdk_stream_is_compressed:
379 * @s: the stream
381 * Check whether stream is compressed.
383 * Returns: 0 if the stream is uncompressed, otherwise the compression
384 * algorithm.
387 cdk_stream_is_compressed (cdk_stream_t s)
389 if (!s)
390 return 0;
391 return s->flags.compressed;
394 void
395 _cdk_stream_set_compress_algo (cdk_stream_t s, int algo)
397 if (!s)
398 return;
399 s->flags.compressed = algo;
403 cdk_error_t
404 cdk_stream_flush (cdk_stream_t s)
406 cdk_error_t rc;
408 if (!s)
410 gnutls_assert ();
411 return CDK_Inv_Value;
414 /* The user callback does not support flush */
415 if (s->cbs_hd)
416 return 0;
418 /* For read-only streams, no flush is needed. */
419 if (!s->flags.write)
420 return 0;
422 if (!s->flags.filtrated)
424 if (!cdk_stream_get_length (s))
425 return 0;
426 rc = cdk_stream_seek (s, 0);
427 if (!rc)
428 rc = stream_flush (s);
429 if (!rc)
430 rc = stream_filter_write (s);
431 s->flags.filtrated = 1;
432 if (rc)
434 s->error = rc;
435 gnutls_assert ();
436 return rc;
439 return 0;
443 void
444 cdk_stream_tmp_set_mode (cdk_stream_t s, int val)
446 if (s && s->flags.temp)
447 s->fmode = val;
452 * cdk_stream_close:
453 * @s: The STREAM object.
455 * Close a stream and flush all buffers. This function work different
456 * for read or write streams. When the stream is for reading, the
457 * filtering is already done and we can simply close the file and all
458 * buffers. But for the case it's a write stream, we need to apply
459 * all registered filters now. The file is closed in the filter
460 * function and not here.
462 cdk_error_t
463 cdk_stream_close (cdk_stream_t s)
465 struct stream_filter_s *f, *f2;
466 cdk_error_t rc;
468 if (!s)
470 gnutls_assert ();
471 return CDK_Inv_Value;
474 #ifdef DEBUG_STREAM
475 _gnutls_read_log ("close stream ref=%d `%s'\n",
476 s->fp_ref, s->fname ? s->fname : "[temp]");
477 #endif
479 /* In the user callback mode, we call the release cb if possible
480 and just free the stream. */
481 if (s->cbs_hd)
483 if (s->cbs.release)
484 rc = s->cbs.release (s->cbs_hd);
485 else
486 rc = 0;
487 cdk_free (s);
488 gnutls_assert ();
489 return rc;
493 rc = 0;
494 if (!s->flags.filtrated && !s->error)
495 rc = cdk_stream_flush (s);
496 if (!s->fp_ref && (s->fname || s->flags.temp))
498 int err;
500 #ifdef DEBUG_STREAM
501 _gnutls_read_log ("close stream fd=%d\n", fileno (s->fp));
502 #endif
503 err = fclose (s->fp);
504 s->fp = NULL;
505 if (err)
506 rc = CDK_File_Error;
509 /* Iterate over the filter list and use the cleanup flag to
510 free the allocated internal structures. */
511 f = s->filters;
512 while (f)
514 f2 = f->next;
515 if (f->fnct)
516 f->fnct (f->uint8_t, STREAMCTL_FREE, NULL, NULL);
517 cdk_free (f);
518 f = f2;
521 if (s->fname)
523 cdk_free (s->fname);
524 s->fname = NULL;
527 cdk_free (s->cache.buf);
528 s->cache.alloced = 0;
530 cdk_free (s);
532 if (rc)
533 gnutls_assert ();
535 return rc;
540 * cdk_stream_eof:
541 * @s: The STREAM object.
543 * Return if the associated file handle was set to EOF. This
544 * function will only work with read streams.
547 cdk_stream_eof (cdk_stream_t s)
549 return s ? s->flags.eof : -1;
553 const char *
554 _cdk_stream_get_fname (cdk_stream_t s)
556 if (!s)
557 return NULL;
558 if (s->flags.temp)
559 return NULL;
560 return s->fname ? s->fname : NULL;
564 /* Return the underlying FP of the stream.
565 WARNING: This handle should not be closed. */
566 FILE *
567 _cdk_stream_get_fp (cdk_stream_t s)
569 return s ? s->fp : NULL;
574 _cdk_stream_get_errno (cdk_stream_t s)
576 return s ? s->error : CDK_Inv_Value;
581 * cdk_stream_get_length:
582 * @s: The STREAM object.
584 * Return the length of the associated file handle. This function
585 * should work for both read and write streams. For write streams an
586 * additional flush is used to write possible pending data.
588 off_t
589 cdk_stream_get_length (cdk_stream_t s)
591 struct stat statbuf;
592 cdk_error_t rc;
594 if (!s)
596 gnutls_assert ();
597 return (off_t) - 1;
600 /* The user callback does not support stat. */
601 if (s->cbs_hd)
602 return 0;
604 rc = stream_flush (s);
605 if (rc)
607 s->error = rc;
608 gnutls_assert ();
609 return (off_t) - 1;
612 if (fstat (fileno (s->fp), &statbuf))
614 s->error = CDK_File_Error;
615 gnutls_assert ();
616 return (off_t) - 1;
619 return statbuf.st_size;
623 static struct stream_filter_s *
624 filter_add2 (cdk_stream_t s)
626 struct stream_filter_s *f;
628 assert (s);
630 f = cdk_calloc (1, sizeof *f);
631 if (!f)
632 return NULL;
633 f->next = s->filters;
634 s->filters = f;
635 return f;
639 static struct stream_filter_s *
640 filter_search (cdk_stream_t s, filter_fnct_t fnc)
642 struct stream_filter_s *f;
644 assert (s);
646 for (f = s->filters; f; f = f->next)
648 if (f->fnct == fnc)
649 return f;
652 return NULL;
655 static inline void
656 set_uint8_t (struct stream_filter_s *f)
658 switch (f->type)
660 case fARMOR:
661 f->uint8_t = &f->u.afx;
662 break;
663 case fCIPHER:
664 f->uint8_t = &f->u.cfx;
665 break;
666 case fLITERAL:
667 f->uint8_t = &f->u.pfx;
668 break;
669 case fCOMPRESS:
670 f->uint8_t = &f->u.zfx;
671 break;
672 case fHASH:
673 f->uint8_t = &f->u.mfx;
674 break;
675 case fTEXT:
676 f->uint8_t = &f->u.tfx;
677 break;
678 default:
679 f->uint8_t = NULL;
684 struct stream_filter_s *
685 filter_add (cdk_stream_t s, filter_fnct_t fnc, int type)
687 struct stream_filter_s *f;
689 assert (s);
691 s->flags.filtrated = 0;
692 f = filter_search (s, fnc);
693 if (f)
694 return f;
695 f = filter_add2 (s);
696 if (!f)
697 return NULL;
698 f->fnct = fnc;
699 f->flags.enabled = 1;
700 f->tmp = NULL;
701 f->type = type;
703 set_uint8_t (f);
705 return f;
708 static int
709 stream_get_mode (cdk_stream_t s)
711 assert (s);
713 if (s->flags.temp)
714 return s->fmode;
715 return s->flags.write;
719 static filter_fnct_t
720 stream_id_to_filter (int type)
722 switch (type)
724 case fARMOR:
725 return _cdk_filter_armor;
726 case fLITERAL:
727 return _cdk_filter_literal;
728 case fTEXT:
729 return _cdk_filter_text;
730 /* case fCIPHER : return _cdk_filter_cipher; */
731 /* case fCOMPRESS: return _cdk_filter_compress; */
732 default:
733 return NULL;
739 * cdk_stream_filter_disable:
740 * @s: The STREAM object
741 * @type: The numberic filter ID.
743 * Disables the filter with the type 'type'.
745 cdk_error_t
746 cdk_stream_filter_disable (cdk_stream_t s, int type)
748 struct stream_filter_s *f;
749 filter_fnct_t fnc;
751 if (!s)
753 gnutls_assert ();
754 return CDK_Inv_Value;
757 fnc = stream_id_to_filter (type);
758 if (!fnc)
760 gnutls_assert ();
761 return CDK_Inv_Value;
763 f = filter_search (s, fnc);
764 if (f)
765 f->flags.enabled = 0;
766 return 0;
770 /* WARNING: tmp should not be closed by the caller. */
771 static cdk_error_t
772 stream_fp_replace (cdk_stream_t s, FILE ** tmp)
774 int rc;
776 assert (s);
778 #ifdef DEBUG_STREAM
779 _gnutls_read_log ("replace stream fd=%d with fd=%d\n",
780 fileno (s->fp), fileno (*tmp));
781 #endif
782 rc = fclose (s->fp);
783 if (rc)
785 s->fp = NULL;
786 gnutls_assert ();
787 return CDK_File_Error;
789 s->fp = *tmp;
790 *tmp = NULL;
791 return 0;
795 /* This function is exactly like filter_read, except the fact that we can't
796 use tmpfile () all the time. That's why we open the real file when there
797 is no last filter. */
798 static cdk_error_t
799 stream_filter_write (cdk_stream_t s)
801 struct stream_filter_s *f;
802 cdk_error_t rc = 0;
804 assert (s);
806 if (s->flags.filtrated)
808 gnutls_assert ();
809 return CDK_Inv_Value;
812 for (f = s->filters; f; f = f->next)
814 if (!f->flags.enabled)
815 continue;
816 /* if there is no next filter, create the final output file */
817 #ifdef DEBUG_STREAM
818 _gnutls_read_log ("filter [write]: last filter=%d fname=%s\n",
819 f->next ? 1 : 0, s->fname);
820 #endif
821 if (!f->next && s->fname)
822 f->tmp = fopen (s->fname, "w+b");
823 else
824 f->tmp = _cdk_tmpfile ();
825 if (!f->tmp)
827 rc = CDK_File_Error;
828 break;
830 /* If there is no next filter, flush the cache. We also do this
831 when the next filter is the armor filter because this filter
832 is special and before it starts, all data should be written. */
833 if ((!f->next || f->next->type == fARMOR) && s->cache.size)
835 rc = stream_cache_flush (s, f->tmp);
836 if (rc)
837 break;
839 rc = f->fnct (f->uint8_t, f->ctl, s->fp, f->tmp);
840 #ifdef DEBUG_STREAM
841 _gnutls_read_log ("filter [write]: type=%d rc=%d\n", f->type, rc);
842 #endif
843 if (!rc)
844 rc = stream_fp_replace (s, &f->tmp);
845 if (!rc)
846 rc = cdk_stream_seek (s, 0);
847 if (rc)
849 #ifdef DEBUG_STREAM
850 _gnutls_read_log ("filter [close]: fd=%d\n", fileno (f->tmp));
851 #endif
852 fclose (f->tmp);
853 f->tmp = NULL;
854 break;
857 return rc;
861 /* Here all data from the file handle is passed through all filters.
862 The scheme works like this:
863 Create a tempfile and use it for the output of the filter. Then the
864 original file handle will be closed and replace with the temp handle.
865 The file pointer will be set to the begin and the game starts again. */
866 static cdk_error_t
867 stream_filter_read (cdk_stream_t s)
869 struct stream_filter_s *f;
870 cdk_error_t rc = 0;
872 assert (s);
874 if (s->flags.filtrated)
875 return 0;
877 for (f = s->filters; f; f = f->next)
879 if (!f->flags.enabled)
880 continue;
881 if (f->flags.error)
883 #ifdef DEBUG_STREAM
884 _gnutls_read_log ("filter %s [read]: has the error flag; skipped\n",
885 s->fname ? s->fname : "[temp]");
886 #endif
887 continue;
890 f->tmp = _cdk_tmpfile ();
891 if (!f->tmp)
893 rc = CDK_File_Error;
894 break;
896 rc = f->fnct (f->uint8_t, f->ctl, s->fp, f->tmp);
897 #ifdef DEBUG_STREAM
898 _gnutls_read_log ("filter %s [read]: type=%d rc=%d\n",
899 s->fname ? s->fname : "[temp]", f->type, rc);
900 #endif
901 if (rc)
903 f->flags.error = 1;
904 break;
907 f->flags.error = 0;
908 /* If the filter is read-only, do not replace the FP because
909 the contents were not altered in any way. */
910 if (!f->flags.rdonly)
912 rc = stream_fp_replace (s, &f->tmp);
913 if (rc)
914 break;
916 else
918 fclose (f->tmp);
919 f->tmp = NULL;
921 rc = cdk_stream_seek (s, 0);
922 if (rc)
923 break;
924 /* Disable the filter after it was successfully used. The idea
925 is the following: let's say the armor filter was pushed and
926 later more filters were added. The second time the filter code
927 will be executed, only the new filter should be started but
928 not the old because we already used it. */
929 f->flags.enabled = 0;
932 return rc;
936 void *
937 _cdk_stream_get_uint8_t (cdk_stream_t s, int fid)
939 struct stream_filter_s *f;
941 if (!s)
942 return NULL;
944 for (f = s->filters; f; f = f->next)
946 if ((int) f->type == fid)
947 return f->uint8_t;
949 return NULL;
954 * cdk_stream_read:
955 * @s: The STREAM object.
956 * @buf: The buffer to insert the readed bytes.
957 * @count: Request so much bytes.
959 * Tries to read count bytes from the STREAM object.
960 * When this function is called the first time, it can take a while
961 * because all filters need to be processed. Please remember that you
962 * need to add the filters in reserved order.
965 cdk_stream_read (cdk_stream_t s, void *buf, size_t buflen)
967 int nread;
968 int rc;
970 if (!s)
972 gnutls_assert ();
973 return EOF;
976 if (s->cbs_hd)
978 if (s->cbs.read)
979 return s->cbs.read (s->cbs_hd, buf, buflen);
980 return 0;
983 if (s->flags.write && !s->flags.temp)
985 s->error = CDK_Inv_Mode;
986 gnutls_assert ();
987 return EOF; /* This is a write stream */
990 if (!s->flags.no_filter && !s->cache.on && !s->flags.filtrated)
992 rc = stream_filter_read (s);
993 if (rc)
995 s->error = rc;
996 if (s->fp && feof (s->fp))
997 s->flags.eof = 1;
998 gnutls_assert ();
999 return EOF;
1001 s->flags.filtrated = 1;
1004 if (!buf && !buflen)
1005 return 0;
1007 nread = fread (buf, 1, buflen, s->fp);
1008 if (!nread)
1009 nread = EOF;
1011 if (feof (s->fp))
1013 s->error = 0;
1014 s->flags.eof = 1;
1016 return nread;
1021 cdk_stream_getc (cdk_stream_t s)
1023 unsigned char buf[2];
1024 int nread;
1026 if (!s)
1028 gnutls_assert ();
1029 return EOF;
1031 nread = cdk_stream_read (s, buf, 1);
1032 if (nread == EOF)
1034 s->error = CDK_File_Error;
1035 gnutls_assert ();
1036 return EOF;
1038 return buf[0];
1043 * cdk_stream_write:
1044 * @s: The STREAM object
1045 * @buf: The buffer with the values to write.
1046 * @count: The size of the buffer.
1048 * Tries to write count bytes into the stream.
1049 * In this function we simply write the bytes to the stream. We can't
1050 * use the filters here because it would mean they have to support
1051 * partial flushing.
1054 cdk_stream_write (cdk_stream_t s, const void *buf, size_t count)
1056 int nwritten;
1058 if (!s)
1060 gnutls_assert ();
1061 return EOF;
1064 if (s->cbs_hd)
1066 if (s->cbs.write)
1067 return s->cbs.write (s->cbs_hd, buf, count);
1068 return 0;
1071 if (!s->flags.write)
1073 s->error = CDK_Inv_Mode; /* this is a read stream */
1074 gnutls_assert ();
1075 return EOF;
1078 if (!buf || !count)
1079 return stream_flush (s);
1081 if (s->cache.on)
1083 #ifdef DEBUG_STREAM
1084 _gnutls_read_log ("stream[ref=%u]: written %d bytes\n", s->fp_ref, (int) count);
1085 #endif
1087 /* We need to resize the buffer if the additional data wouldn't
1088 fit into it. We allocate more memory to avoid to resize it the
1089 next time the function is used. */
1090 if (s->cache.size + count > s->cache.alloced)
1092 byte *old = s->cache.buf;
1094 s->cache.buf =
1095 cdk_calloc (1, s->cache.alloced + count + STREAM_BUFSIZE);
1096 s->cache.alloced += (count + STREAM_BUFSIZE);
1097 memcpy (s->cache.buf, old, s->cache.size);
1098 cdk_free (old);
1099 #ifdef DEBUG_STREAM
1100 _gnutls_read_log ("stream: enlarge cache to %d octets\n",
1101 (int) s->cache.alloced);
1102 #endif
1105 memcpy (s->cache.buf + s->cache.size, buf, count);
1106 s->cache.size += count;
1107 return count;
1110 #ifdef DEBUG_STREAM
1111 _gnutls_read_log ("stream[fd=%u]: written %d bytes\n", fileno (s->fp), (int) count);
1112 #endif
1114 nwritten = fwrite (buf, 1, count, s->fp);
1115 if (!nwritten)
1116 nwritten = EOF;
1117 return nwritten;
1122 cdk_stream_putc (cdk_stream_t s, int c)
1124 byte buf[2];
1125 int nwritten;
1127 if (!s)
1129 gnutls_assert ();
1130 return EOF;
1132 buf[0] = c;
1133 nwritten = cdk_stream_write (s, buf, 1);
1134 if (nwritten == EOF)
1135 return EOF;
1136 return 0;
1140 off_t
1141 cdk_stream_tell (cdk_stream_t s)
1143 return s ? ftell (s->fp) : (off_t) - 1;
1147 cdk_error_t
1148 cdk_stream_seek (cdk_stream_t s, off_t offset)
1150 off_t len;
1152 if (!s)
1154 gnutls_assert ();
1155 return CDK_Inv_Value;
1158 if (s->cbs_hd)
1160 if (s->cbs.seek)
1161 return s->cbs.seek (s->cbs_hd, offset);
1162 return 0;
1165 /* Set or reset the EOF flag. */
1166 len = cdk_stream_get_length (s);
1167 if (len == offset)
1168 s->flags.eof = 1;
1169 else
1170 s->flags.eof = 0;
1172 if (fseek (s->fp, offset, SEEK_SET))
1174 gnutls_assert ();
1175 return CDK_File_Error;
1177 return 0;
1181 static cdk_error_t
1182 stream_flush (cdk_stream_t s)
1184 assert (s);
1186 /* For some constellations it cannot be assured that the
1187 return value is defined, thus we ignore it for now. */
1188 (void) fflush (s->fp);
1189 return 0;
1194 * cdk_stream_set_armor_flag:
1195 * @s: the stream object
1196 * @type: the type of armor to use
1198 * If the file is in read-mode, no armor type needs to be
1199 * defined (armor_type=0) because the armor filter will be
1200 * used for decoding existing armor data.
1201 * For the write mode, @armor_type can be set to any valid
1202 * armor type (message, key, sig).
1204 cdk_error_t
1205 cdk_stream_set_armor_flag (cdk_stream_t s, int armor_type)
1207 struct stream_filter_s *f;
1209 if (!s)
1211 gnutls_assert ();
1212 return CDK_Inv_Value;
1214 f = filter_add (s, _cdk_filter_armor, fARMOR);
1215 if (!f)
1217 gnutls_assert ();
1218 return CDK_Out_Of_Core;
1220 f->u.afx.idx = f->u.afx.idx2 = armor_type;
1221 f->ctl = stream_get_mode (s);
1222 return 0;
1227 * cdk_stream_set_literal_flag:
1228 * @s: the stream object
1229 * @mode: the mode to use (binary, text, unicode)
1230 * @fname: the file name to store in the packet.
1232 * In read mode it kicks off the literal decoding routine to
1233 * unwrap the data from the packet. The @mode parameter is ignored.
1234 * In write mode the function can be used to wrap the stream data
1235 * into a literal packet with the given mode and file name.
1237 cdk_error_t
1238 cdk_stream_set_literal_flag (cdk_stream_t s, cdk_lit_format_t mode,
1239 const char *fname)
1241 struct stream_filter_s *f;
1242 const char *orig_fname;
1244 #ifdef DEBUG_STREAM
1245 _gnutls_read_log ("stream: enable literal mode.\n");
1246 #endif
1248 if (!s)
1250 gnutls_assert ();
1251 return CDK_Inv_Value;
1254 orig_fname = _cdk_stream_get_fname (s);
1255 f = filter_add (s, _cdk_filter_literal, fLITERAL);
1256 if (!f)
1258 gnutls_assert ();
1259 return CDK_Out_Of_Core;
1261 f->u.pfx.mode = mode;
1262 f->u.pfx.filename = fname ? cdk_strdup (fname) : NULL;
1263 f->u.pfx.orig_filename = orig_fname ? cdk_strdup (orig_fname) : NULL;
1264 f->ctl = stream_get_mode (s);
1265 if (s->blkmode > 0)
1267 f->u.pfx.blkmode.on = 1;
1268 f->u.pfx.blkmode.size = s->blkmode;
1270 return 0;
1275 * cdk_stream_set_compress_flag:
1276 * @s: the stream object
1277 * @algo: the compression algo
1278 * @level: level of compression (0..9)
1280 * In read mode it kicks off the decompression filter to retrieve
1281 * the uncompressed data.
1282 * In write mode the stream data will be compressed with the
1283 * given algorithm at the given level.
1285 cdk_error_t
1286 cdk_stream_set_compress_flag (cdk_stream_t s, int algo, int level)
1289 gnutls_assert ();
1290 return CDK_Not_Implemented;
1295 * cdk_stream_set_text_flag:
1296 * @s: the stream object
1297 * @lf: line ending
1299 * Pushes the text filter to store the stream data in cannoncial format.
1301 cdk_error_t
1302 cdk_stream_set_text_flag (cdk_stream_t s, const char *lf)
1304 struct stream_filter_s *f;
1306 if (!s)
1308 gnutls_assert ();
1309 return CDK_Inv_Value;
1311 f = filter_add (s, _cdk_filter_text, fTEXT);
1312 if (!f)
1314 gnutls_assert ();
1315 return CDK_Out_Of_Core;
1317 f->ctl = stream_get_mode (s);
1318 f->u.tfx.lf = lf;
1319 return 0;
1324 * cdk_stream_set_hash_flag:
1325 * @s: the stream object
1326 * @digest_algo: the digest algorithm to use
1328 * This is for read-only streams. It pushes a digest filter to
1329 * calculate the digest of the given stream data.
1331 cdk_error_t
1332 cdk_stream_set_hash_flag (cdk_stream_t s, int digest_algo)
1334 struct stream_filter_s *f;
1336 if (!s)
1338 gnutls_assert ();
1339 return CDK_Inv_Value;
1341 if (stream_get_mode (s))
1343 gnutls_assert ();
1344 return CDK_Inv_Mode;
1346 f = filter_add (s, _cdk_filter_hash, fHASH);
1347 if (!f)
1349 gnutls_assert ();
1350 return CDK_Out_Of_Core;
1352 f->ctl = stream_get_mode (s);
1353 f->u.mfx.digest_algo = digest_algo;
1354 f->flags.rdonly = 1;
1355 return 0;
1360 * cdk_stream_enable_cache:
1361 * @s: the stream object
1362 * @val: 1=on, 0=off
1364 * Enables or disable the cache section of a stream object.
1366 cdk_error_t
1367 cdk_stream_enable_cache (cdk_stream_t s, int val)
1369 if (!s)
1371 gnutls_assert ();
1372 return CDK_Inv_Value;
1374 if (!s->flags.write)
1376 gnutls_assert ();
1377 return CDK_Inv_Mode;
1379 s->cache.on = val;
1380 if (!s->cache.buf)
1382 s->cache.buf = cdk_calloc (1, STREAM_BUFSIZE);
1383 s->cache.alloced = STREAM_BUFSIZE;
1384 #ifdef DEBUG_STREAM
1385 _gnutls_read_log ("stream: allocate cache of %d octets\n",
1386 STREAM_BUFSIZE);
1387 #endif
1389 return 0;
1393 static int
1394 stream_cache_flush (cdk_stream_t s, FILE * fp)
1396 int nwritten;
1398 assert (s);
1400 /* FIXME: We should find a way to use cdk_stream_write here. */
1401 if (s->cache.size > 0)
1403 nwritten = fwrite (s->cache.buf, 1, s->cache.size, fp);
1404 if (!nwritten)
1406 gnutls_assert ();
1407 return CDK_File_Error;
1409 s->cache.size = 0;
1410 s->cache.on = 0;
1411 memset (s->cache.buf, 0, s->cache.alloced);
1413 return 0;
1418 * cdk_stream_kick_off:
1419 * @inp: the input stream
1420 * @out: the output stream.
1422 * Passes the entire data from @inp into the output stream @out
1423 * with all the activated filters.
1425 cdk_error_t
1426 cdk_stream_kick_off (cdk_stream_t inp, cdk_stream_t out)
1428 byte buf[BUFSIZE];
1429 int nread, nwritten;
1430 cdk_error_t rc;
1432 if (!inp || !out)
1434 gnutls_assert ();
1435 return CDK_Inv_Value;
1437 rc = CDK_Success;
1438 while (!cdk_stream_eof (inp))
1440 nread = cdk_stream_read (inp, buf, DIM (buf));
1441 if (!nread || nread == EOF)
1442 break;
1443 nwritten = cdk_stream_write (out, buf, nread);
1444 if (!nwritten || nwritten == EOF)
1445 { /* In case of errors, we leave the loop. */
1446 rc = inp->error;
1447 break;
1451 memset (buf, 0, sizeof (buf));
1452 return rc;
1457 * cdk_stream_mmap_part:
1458 * @s: the stream
1459 * @off: the offset where to start
1460 * @len: how much bytes shall be mapped
1461 * @ret_buf: the buffer to store the content
1462 * @ret_buflen: length of the buffer
1464 * Maps the data of the given stream into a memory section. @ret_count
1465 * contains the length of the buffer.
1467 cdk_error_t
1468 cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t len,
1469 byte ** ret_buf, size_t * ret_buflen)
1471 cdk_error_t rc;
1472 off_t oldpos;
1473 unsigned int n;
1475 if (!ret_buf || !ret_buflen)
1477 gnutls_assert ();
1478 return CDK_Inv_Value;
1480 *ret_buf = NULL;
1481 *ret_buflen = 0;
1483 if (!s)
1485 gnutls_assert ();
1486 return CDK_Inv_Value;
1489 /* Memory mapping is not supported on custom I/O objects. */
1490 if (s->cbs_hd)
1492 #ifdef DEBUG_STREAM
1493 _gnutls_read_log ("cdk_stream_mmap_part: not supported on callbacks\n");
1494 #endif
1495 gnutls_assert ();
1496 return CDK_Inv_Mode;
1499 oldpos = cdk_stream_tell (s);
1500 rc = cdk_stream_flush (s);
1501 if (rc)
1503 gnutls_assert ();
1504 return rc;
1506 rc = cdk_stream_seek (s, off);
1507 if (rc)
1509 gnutls_assert ();
1510 return rc;
1512 if (!len)
1513 len = cdk_stream_get_length (s);
1514 if (!len)
1516 _gnutls_read_log ("cdk_stream_mmap_part: invalid file size %lu\n", (unsigned long)len);
1517 gnutls_assert ();
1518 return s->error;
1520 if (len > MAX_MAP_SIZE)
1522 gnutls_assert ();
1523 return CDK_Too_Short;
1526 *ret_buf = cdk_calloc (1, len + 1);
1527 *ret_buflen = len;
1528 n = cdk_stream_read (s, *ret_buf, len);
1529 if (n != len)
1530 *ret_buflen = n;
1531 rc = cdk_stream_seek (s, oldpos);
1532 if (rc)
1533 gnutls_assert ();
1534 return rc;
1538 cdk_error_t
1539 cdk_stream_mmap (cdk_stream_t inp, byte ** buf, size_t * buflen)
1541 off_t len;
1543 /* We need to make sure all data is flushed before we retrieve the size. */
1544 cdk_stream_flush (inp);
1545 len = cdk_stream_get_length (inp);
1546 return cdk_stream_mmap_part (inp, 0, len, buf, buflen);
1551 * cdk_stream_peek:
1552 * @inp: the input stream handle
1553 * @s: buffer
1554 * @count: number of bytes to peek
1556 * The function acts like cdk_stream_read with the difference that
1557 * the file pointer is moved to the old position after the bytes were read.
1560 cdk_stream_peek (cdk_stream_t inp, byte * buf, size_t buflen)
1562 off_t off;
1563 int nbytes;
1565 if (!inp || !buf)
1566 return 0;
1567 if (inp->cbs_hd)
1568 return 0;
1570 off = cdk_stream_tell (inp);
1571 nbytes = cdk_stream_read (inp, buf, buflen);
1572 if (nbytes == -1)
1573 return 0;
1574 if (cdk_stream_seek (inp, off))
1575 return 0;
1576 return nbytes;
1580 /* Try to read a line from the given stream. */
1582 _cdk_stream_gets (cdk_stream_t s, char *buf, size_t count)
1584 int c, i;
1586 assert (s);
1588 i = 0;
1589 while (!cdk_stream_eof (s) && count > 0)
1591 c = cdk_stream_getc (s);
1592 if (c == EOF || c == '\r' || c == '\n')
1594 buf[i++] = '\0';
1595 break;
1597 buf[i++] = c;
1598 count--;
1600 return i;
1604 /* Try to write string into the stream @s. */
1606 _cdk_stream_puts (cdk_stream_t s, const char *buf)
1608 return cdk_stream_write (s, buf, strlen (buf));
1612 /* Activate the block mode for the given stream. */
1613 cdk_error_t
1614 _cdk_stream_set_blockmode (cdk_stream_t s, size_t nbytes)
1616 assert (s);
1618 #ifdef DEBUG_STREAM
1619 _gnutls_read_log ("stream: activate block mode with blocksize %d\n",
1620 (int) nbytes);
1621 #endif
1622 s->blkmode = nbytes;
1623 return 0;
1627 /* Return the block mode state of the given stream. */
1629 _cdk_stream_get_blockmode (cdk_stream_t s)
1631 return s ? s->blkmode : 0;