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