raw
mpi-genesis             1 /* iobuf.c  -  file handling
mpi-genesis 2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2008,
mpi-genesis 3 * 2009 Free Software Foundation, Inc.
mpi-genesis 4 *
mpi-genesis 5 * This file is part of GnuPG.
mpi-genesis 6 *
mpi-genesis 7 * GnuPG is free software; you can redistribute it and/or modify
mpi-genesis 8 * it under the terms of the GNU General Public License as published by
mpi-genesis 9 * the Free Software Foundation; either version 3 of the License, or
mpi-genesis 10 * (at your option) any later version.
mpi-genesis 11 *
mpi-genesis 12 * GnuPG is distributed in the hope that it will be useful,
mpi-genesis 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mpi-genesis 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
mpi-genesis 15 * GNU General Public License for more details.
mpi-genesis 16 *
mpi-genesis 17 * You should have received a copy of the GNU General Public License
mpi-genesis 18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
mpi-genesis 19 */
mpi-genesis 20
mpi-genesis 21 #include <config.h>
mpi-genesis 22 #include <stdio.h>
mpi-genesis 23 #include <stdlib.h>
mpi-genesis 24 #include <string.h>
mpi-genesis 25 #include <errno.h>
mpi-genesis 26 #include <ctype.h>
mpi-genesis 27 #include <assert.h>
mpi-genesis 28 #include <sys/types.h>
mpi-genesis 29 #include <sys/stat.h>
mpi-genesis 30 #include <fcntl.h>
mpi-genesis 31 #include <unistd.h>
mpi-genesis 32 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 33 #include <windows.h>
mpi-genesis 34 #endif
mpi-genesis 35 #ifdef __riscos__
mpi-genesis 36 #include <kernel.h>
mpi-genesis 37 #include <swis.h>
mpi-genesis 38 #endif /* __riscos__ */
mpi-genesis 39
mpi-genesis 40 #include "memory.h"
mpi-genesis 41 #include "util.h"
mpi-genesis 42 #include "iobuf.h"
mpi-genesis 43
mpi-genesis 44 /* The size of the internal buffers.
mpi-genesis 45 NOTE: If you change this value you MUST also adjust the regression
mpi-genesis 46 test "armored_key_8192" in armor.test! */
mpi-genesis 47 #define IOBUF_BUFFER_SIZE 8192
mpi-genesis 48
mpi-genesis 49
mpi-genesis 50 #undef FILE_FILTER_USES_STDIO
mpi-genesis 51
mpi-genesis 52 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 53 #define USE_SETMODE 1
mpi-genesis 54 #endif
mpi-genesis 55
mpi-genesis 56 #ifdef FILE_FILTER_USES_STDIO
mpi-genesis 57 #define my_fileno(a) fileno ((a))
mpi-genesis 58 #define my_fopen_ro(a,b) fopen ((a),(b))
mpi-genesis 59 #define my_fopen(a,b) fopen ((a),(b))
mpi-genesis 60 typedef FILE *FILEP_OR_FD;
mpi-genesis 61 #define INVALID_FP NULL
mpi-genesis 62 #define FILEP_OR_FD_FOR_STDIN (stdin)
mpi-genesis 63 #define FILEP_OR_FD_FOR_STDOUT (stdout)
mpi-genesis 64 typedef struct {
mpi-genesis 65 FILE *fp; /* open file handle */
mpi-genesis 66 int keep_open;
mpi-genesis 67 int no_cache;
mpi-genesis 68 int print_only_name; /* flags indicating that fname is not a real file*/
mpi-genesis 69 char fname[1]; /* name of the file */
mpi-genesis 70 } file_filter_ctx_t ;
mpi-genesis 71 #else
mpi-genesis 72 #define my_fileno(a) (a)
mpi-genesis 73 #define my_fopen_ro(a,b) fd_cache_open ((a),(b))
mpi-genesis 74 #define my_fopen(a,b) direct_open ((a),(b))
mpi-genesis 75 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 76 typedef HANDLE FILEP_OR_FD;
mpi-genesis 77 #define INVALID_FP ((HANDLE)-1)
mpi-genesis 78 #define FILEP_OR_FD_FOR_STDIN (GetStdHandle (STD_INPUT_HANDLE))
mpi-genesis 79 #define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
mpi-genesis 80 #undef USE_SETMODE
mpi-genesis 81 #else
mpi-genesis 82 typedef int FILEP_OR_FD;
mpi-genesis 83 #define INVALID_FP (-1)
mpi-genesis 84 #define FILEP_OR_FD_FOR_STDIN (0)
mpi-genesis 85 #define FILEP_OR_FD_FOR_STDOUT (1)
mpi-genesis 86 #endif
mpi-genesis 87 typedef struct {
mpi-genesis 88 FILEP_OR_FD fp; /* open file handle */
mpi-genesis 89 int keep_open;
mpi-genesis 90 int no_cache;
mpi-genesis 91 int eof_seen;
mpi-genesis 92 int print_only_name; /* flags indicating that fname is not a real file*/
mpi-genesis 93 char fname[1]; /* name of the file */
mpi-genesis 94 } file_filter_ctx_t ;
mpi-genesis 95
mpi-genesis 96 struct close_cache_s {
mpi-genesis 97 struct close_cache_s *next;
mpi-genesis 98 FILEP_OR_FD fp;
mpi-genesis 99 char fname[1];
mpi-genesis 100 };
mpi-genesis 101 typedef struct close_cache_s *CLOSE_CACHE;
mpi-genesis 102 static CLOSE_CACHE close_cache;
mpi-genesis 103 #endif
mpi-genesis 104
mpi-genesis 105 #ifdef _WIN32
mpi-genesis 106 typedef struct {
mpi-genesis 107 int sock;
mpi-genesis 108 int keep_open;
mpi-genesis 109 int no_cache;
mpi-genesis 110 int eof_seen;
mpi-genesis 111 int print_only_name; /* flags indicating that fname is not a real file*/
mpi-genesis 112 char fname[1]; /* name of the file */
mpi-genesis 113 } sock_filter_ctx_t ;
mpi-genesis 114 #endif /*_WIN32*/
mpi-genesis 115
mpi-genesis 116 /* The first partial length header block must be of size 512
mpi-genesis 117 * to make it easier (and efficienter) we use a min. block size of 512
mpi-genesis 118 * for all chunks (but the last one) */
mpi-genesis 119 #define OP_MIN_PARTIAL_CHUNK 512
mpi-genesis 120 #define OP_MIN_PARTIAL_CHUNK_2POW 9
mpi-genesis 121
mpi-genesis 122 typedef struct {
mpi-genesis 123 int use;
mpi-genesis 124 size_t size;
mpi-genesis 125 size_t count;
mpi-genesis 126 int partial; /* 1 = partial header, 2 in last partial packet */
mpi-genesis 127 char *buffer; /* used for partial header */
mpi-genesis 128 size_t buflen; /* used size of buffer */
mpi-genesis 129 int first_c; /* of partial header (which is > 0)*/
mpi-genesis 130 int eof;
mpi-genesis 131 } block_filter_ctx_t;
mpi-genesis 132
mpi-genesis 133 static int special_names_enabled;
mpi-genesis 134
mpi-genesis 135 static int underflow(IOBUF a);
mpi-genesis 136 static int translate_file_handle ( int fd, int for_write );
mpi-genesis 137
mpi-genesis 138
mpi-genesis 139
mpi-genesis 140 #ifndef FILE_FILTER_USES_STDIO
mpi-genesis 141
mpi-genesis 142 /* This is a replacement for strcmp. Under W32 it does not
mpi-genesis 143 distinguish between backslash and slash. */
mpi-genesis 144 static int
mpi-genesis 145 fd_cache_strcmp (const char *a, const char *b)
mpi-genesis 146 {
mpi-genesis 147 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 148 for (; *a && *b; a++, b++)
mpi-genesis 149 {
mpi-genesis 150 if (*a != *b && !((*a == '/' && *b == '\\')
mpi-genesis 151 || (*a == '\\' && *b == '/')) )
mpi-genesis 152 break;
mpi-genesis 153 }
mpi-genesis 154 return *(const unsigned char *)a - *(const unsigned char *)b;
mpi-genesis 155 #else
mpi-genesis 156 return strcmp (a, b);
mpi-genesis 157 #endif
mpi-genesis 158 }
mpi-genesis 159
mpi-genesis 160 /*
mpi-genesis 161 * Invalidate (i.e. close) a cached iobuf or all iobufs if NULL is
mpi-genesis 162 * used for FNAME.
mpi-genesis 163 */
mpi-genesis 164 static int
mpi-genesis 165 fd_cache_invalidate (const char *fname)
mpi-genesis 166 {
mpi-genesis 167 CLOSE_CACHE cc;
mpi-genesis 168 int err=0;
mpi-genesis 169
mpi-genesis 170 if (!fname) {
mpi-genesis 171 if( DBG_IOBUF )
mpi-genesis 172 log_debug ("fd_cache_invalidate (all)\n");
mpi-genesis 173
mpi-genesis 174 for (cc=close_cache; cc; cc = cc->next ) {
mpi-genesis 175 if ( cc->fp != INVALID_FP ) {
mpi-genesis 176 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 177 CloseHandle (cc->fp);
mpi-genesis 178 #else
mpi-genesis 179 close(cc->fp);
mpi-genesis 180 #endif
mpi-genesis 181 cc->fp = INVALID_FP;
mpi-genesis 182 }
mpi-genesis 183 }
mpi-genesis 184 return err;
mpi-genesis 185 }
mpi-genesis 186
mpi-genesis 187 if( DBG_IOBUF )
mpi-genesis 188 log_debug ("fd_cache_invalidate (%s)\n", fname);
mpi-genesis 189
mpi-genesis 190 for (cc=close_cache; cc; cc = cc->next ) {
mpi-genesis 191 if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
mpi-genesis 192 if( DBG_IOBUF )
mpi-genesis 193 log_debug (" did (%s)\n", cc->fname);
mpi-genesis 194 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 195 if(CloseHandle (cc->fp)==0)
mpi-genesis 196 err=-1;
mpi-genesis 197 #else
mpi-genesis 198 err=close(cc->fp);
mpi-genesis 199 #endif
mpi-genesis 200 cc->fp = INVALID_FP;
mpi-genesis 201 }
mpi-genesis 202 }
mpi-genesis 203
mpi-genesis 204 return err;
mpi-genesis 205 }
mpi-genesis 206
mpi-genesis 207 static int
mpi-genesis 208 fd_cache_synchronize(const char *fname)
mpi-genesis 209 {
mpi-genesis 210 int err=0;
mpi-genesis 211
mpi-genesis 212 #ifndef HAVE_DOSISH_SYSTEM
mpi-genesis 213 CLOSE_CACHE cc;
mpi-genesis 214
mpi-genesis 215 if( DBG_IOBUF )
mpi-genesis 216 log_debug ("fd_cache_synchronize (%s)\n", fname);
mpi-genesis 217
mpi-genesis 218 for (cc=close_cache; cc; cc = cc->next )
mpi-genesis 219 {
mpi-genesis 220 if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) )
mpi-genesis 221 {
mpi-genesis 222 if( DBG_IOBUF )
mpi-genesis 223 log_debug (" did (%s)\n", cc->fname);
mpi-genesis 224
mpi-genesis 225 err=fsync(cc->fp);
mpi-genesis 226 }
mpi-genesis 227 }
mpi-genesis 228 #endif
mpi-genesis 229
mpi-genesis 230 return err;
mpi-genesis 231 }
mpi-genesis 232
mpi-genesis 233 static FILEP_OR_FD
mpi-genesis 234 direct_open (const char *fname, const char *mode)
mpi-genesis 235 {
mpi-genesis 236 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 237 unsigned long da, cd, sm;
mpi-genesis 238 HANDLE hfile;
mpi-genesis 239
mpi-genesis 240 /* Note, that we do not handle all mode combinations */
mpi-genesis 241
mpi-genesis 242 /* According to the ReactOS source it seems that open() of the
mpi-genesis 243 * standard MSW32 crt does open the file in share mode which is
mpi-genesis 244 * something new for MS applications ;-)
mpi-genesis 245 */
mpi-genesis 246 if ( strchr (mode, '+') ) {
mpi-genesis 247 fd_cache_invalidate (fname);
mpi-genesis 248 da = GENERIC_READ|GENERIC_WRITE;
mpi-genesis 249 cd = OPEN_EXISTING;
mpi-genesis 250 sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
mpi-genesis 251 }
mpi-genesis 252 else if ( strchr (mode, 'w') ) {
mpi-genesis 253 fd_cache_invalidate (fname);
mpi-genesis 254 da = GENERIC_WRITE;
mpi-genesis 255 cd = CREATE_ALWAYS;
mpi-genesis 256 sm = FILE_SHARE_WRITE;
mpi-genesis 257 }
mpi-genesis 258 else {
mpi-genesis 259 da = GENERIC_READ;
mpi-genesis 260 cd = OPEN_EXISTING;
mpi-genesis 261 sm = FILE_SHARE_READ;
mpi-genesis 262 }
mpi-genesis 263
mpi-genesis 264 hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL);
mpi-genesis 265 return hfile;
mpi-genesis 266 #else
mpi-genesis 267 int oflag;
mpi-genesis 268 int cflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
mpi-genesis 269
mpi-genesis 270 /* Note, that we do not handle all mode combinations */
mpi-genesis 271 if ( strchr (mode, '+') ) {
mpi-genesis 272 fd_cache_invalidate (fname);
mpi-genesis 273 oflag = O_RDWR;
mpi-genesis 274 }
mpi-genesis 275 else if ( strchr (mode, 'w') ) {
mpi-genesis 276 fd_cache_invalidate (fname);
mpi-genesis 277 oflag = O_WRONLY | O_CREAT | O_TRUNC;
mpi-genesis 278 }
mpi-genesis 279 else {
mpi-genesis 280 oflag = O_RDONLY;
mpi-genesis 281 }
mpi-genesis 282 #ifdef O_BINARY
mpi-genesis 283 if (strchr (mode, 'b'))
mpi-genesis 284 oflag |= O_BINARY;
mpi-genesis 285 #endif
mpi-genesis 286 #ifndef __riscos__
mpi-genesis 287 return open (fname, oflag, cflag );
mpi-genesis 288 #else
mpi-genesis 289 {
mpi-genesis 290 struct stat buf;
mpi-genesis 291 int rc = stat( fname, &buf );
mpi-genesis 292
mpi-genesis 293 /* Don't allow iobufs on directories */
mpi-genesis 294 if( !rc && S_ISDIR(buf.st_mode) && !S_ISREG(buf.st_mode) )
mpi-genesis 295 return __set_errno( EISDIR );
mpi-genesis 296 else
mpi-genesis 297 return open( fname, oflag, cflag );
mpi-genesis 298 }
mpi-genesis 299 #endif
mpi-genesis 300 #endif
mpi-genesis 301 }
mpi-genesis 302
mpi-genesis 303
mpi-genesis 304 /*
mpi-genesis 305 * Instead of closing an FD we keep it open and cache it for later reuse
mpi-genesis 306 * Note that this caching strategy only works if the process does not chdir.
mpi-genesis 307 */
mpi-genesis 308 static void
mpi-genesis 309 fd_cache_close (const char *fname, FILEP_OR_FD fp)
mpi-genesis 310 {
mpi-genesis 311 CLOSE_CACHE cc;
mpi-genesis 312
mpi-genesis 313 assert (fp);
mpi-genesis 314 if ( !fname || !*fname ) {
mpi-genesis 315 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 316 CloseHandle (fp);
mpi-genesis 317 #else
mpi-genesis 318 close(fp);
mpi-genesis 319 #endif
mpi-genesis 320 if( DBG_IOBUF )
mpi-genesis 321 log_debug ("fd_cache_close (%d) real\n", (int)fp);
mpi-genesis 322 return;
mpi-genesis 323 }
mpi-genesis 324 /* try to reuse a slot */
mpi-genesis 325 for (cc=close_cache; cc; cc = cc->next ) {
mpi-genesis 326 if ( cc->fp == INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
mpi-genesis 327 cc->fp = fp;
mpi-genesis 328 if( DBG_IOBUF )
mpi-genesis 329 log_debug ("fd_cache_close (%s) used existing slot\n", fname);
mpi-genesis 330 return;
mpi-genesis 331 }
mpi-genesis 332 }
mpi-genesis 333 /* add a new one */
mpi-genesis 334 if( DBG_IOBUF )
mpi-genesis 335 log_debug ("fd_cache_close (%s) new slot created\n", fname);
mpi-genesis 336 cc = xmalloc_clear (sizeof *cc + strlen (fname));
mpi-genesis 337 strcpy (cc->fname, fname);
mpi-genesis 338 cc->fp = fp;
mpi-genesis 339 cc->next = close_cache;
mpi-genesis 340 close_cache = cc;
mpi-genesis 341 }
mpi-genesis 342
mpi-genesis 343 /*
mpi-genesis 344 * Do an direct_open on FNAME but first try to reuse one from the fd_cache
mpi-genesis 345 */
mpi-genesis 346 static FILEP_OR_FD
mpi-genesis 347 fd_cache_open (const char *fname, const char *mode)
mpi-genesis 348 {
mpi-genesis 349 CLOSE_CACHE cc;
mpi-genesis 350
mpi-genesis 351 assert (fname);
mpi-genesis 352 for (cc=close_cache; cc; cc = cc->next ) {
mpi-genesis 353 if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
mpi-genesis 354 FILEP_OR_FD fp = cc->fp;
mpi-genesis 355 cc->fp = INVALID_FP;
mpi-genesis 356 if( DBG_IOBUF )
mpi-genesis 357 log_debug ("fd_cache_open (%s) using cached fp\n", fname);
mpi-genesis 358 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 359 if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff ) {
mpi-genesis 360 log_error ("rewind file failed on handle %p: %s\n",
mpi-genesis 361 fp, w32_strerror (errno));
mpi-genesis 362 fp = INVALID_FP;
mpi-genesis 363 }
mpi-genesis 364 #else
mpi-genesis 365 if ( lseek (fp, 0, SEEK_SET) == (off_t)-1 ) {
mpi-genesis 366 log_error("can't rewind fd %d: %s\n", fp, strerror(errno) );
mpi-genesis 367 fp = INVALID_FP;
mpi-genesis 368 }
mpi-genesis 369 #endif
mpi-genesis 370 return fp;
mpi-genesis 371 }
mpi-genesis 372 }
mpi-genesis 373 if( DBG_IOBUF )
mpi-genesis 374 log_debug ("fd_cache_open (%s) not cached\n", fname);
mpi-genesis 375 return direct_open (fname, mode);
mpi-genesis 376 }
mpi-genesis 377
mpi-genesis 378
mpi-genesis 379 #endif /*FILE_FILTER_USES_STDIO*/
mpi-genesis 380
mpi-genesis 381
mpi-genesis 382 /****************
mpi-genesis 383 * Read data from a file into buf which has an allocated length of *LEN.
mpi-genesis 384 * return the number of read bytes in *LEN. OPAQUE is the FILE * of
mpi-genesis 385 * the stream. A is not used.
mpi-genesis 386 * control may be:
mpi-genesis 387 * IOBUFCTRL_INIT: called just before the function is linked into the
mpi-genesis 388 * list of function. This can be used to prepare internal
mpi-genesis 389 * data structures of the function.
mpi-genesis 390 * IOBUFCTRL_FREE: called just before the function is removed from the
mpi-genesis 391 * list of functions and can be used to release internal
mpi-genesis 392 * data structures or close a file etc.
mpi-genesis 393 * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
mpi-genesis 394 * with new stuff. *RET_LEN is the available size of the
mpi-genesis 395 * buffer, and should be set to the number of bytes
mpi-genesis 396 * which were put into the buffer. The function
mpi-genesis 397 * returns 0 to indicate success, -1 on EOF and
mpi-genesis 398 * G10ERR_xxxxx for other errors.
mpi-genesis 399 *
mpi-genesis 400 * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
mpi-genesis 401 * *RET_LAN is the number of bytes in BUF.
mpi-genesis 402 *
mpi-genesis 403 * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel. The
mpi-genesis 404 * filter may take appropriate action on this message.
mpi-genesis 405 */
mpi-genesis 406 static int
mpi-genesis 407 file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
mpi-genesis 408 {
mpi-genesis 409 file_filter_ctx_t *a = opaque;
mpi-genesis 410 FILEP_OR_FD f = a->fp;
mpi-genesis 411 size_t size = *ret_len;
mpi-genesis 412 size_t nbytes = 0;
mpi-genesis 413 int rc = 0;
mpi-genesis 414
mpi-genesis 415 #ifdef FILE_FILTER_USES_STDIO
mpi-genesis 416 if( control == IOBUFCTRL_UNDERFLOW ) {
mpi-genesis 417 assert( size ); /* need a buffer */
mpi-genesis 418 if ( feof(f)) { /* On terminals you could easiely read as many EOFs as you call */
mpi-genesis 419 rc = -1; /* fread() or fgetc() repeatly. Every call will block until you press */
mpi-genesis 420 *ret_len = 0; /* CTRL-D. So we catch this case before we call fread() again. */
mpi-genesis 421 }
mpi-genesis 422 else {
mpi-genesis 423 clearerr( f );
mpi-genesis 424 nbytes = fread( buf, 1, size, f );
mpi-genesis 425 if( feof(f) && !nbytes ) {
mpi-genesis 426 rc = -1; /* okay: we can return EOF now. */
mpi-genesis 427 }
mpi-genesis 428 else if( ferror(f) && errno != EPIPE ) {
mpi-genesis 429 log_error("%s: read error: %s\n",
mpi-genesis 430 a->fname, strerror(errno));
mpi-genesis 431 rc = G10ERR_READ_FILE;
mpi-genesis 432 }
mpi-genesis 433 *ret_len = nbytes;
mpi-genesis 434 }
mpi-genesis 435 }
mpi-genesis 436 else if( control == IOBUFCTRL_FLUSH ) {
mpi-genesis 437 if( size ) {
mpi-genesis 438 clearerr( f );
mpi-genesis 439 nbytes = fwrite( buf, 1, size, f );
mpi-genesis 440 if( ferror(f) ) {
mpi-genesis 441 log_error("%s: write error: %s\n", a->fname, strerror(errno));
mpi-genesis 442 rc = G10ERR_WRITE_FILE;
mpi-genesis 443 }
mpi-genesis 444 }
mpi-genesis 445 *ret_len = nbytes;
mpi-genesis 446 }
mpi-genesis 447 else if( control == IOBUFCTRL_INIT ) {
mpi-genesis 448 a->keep_open = a->no_cache = 0;
mpi-genesis 449 }
mpi-genesis 450 else if( control == IOBUFCTRL_DESC ) {
mpi-genesis 451 *(char**)buf = "file_filter";
mpi-genesis 452 }
mpi-genesis 453 else if( control == IOBUFCTRL_FREE ) {
mpi-genesis 454 if( f != stdin && f != stdout ) {
mpi-genesis 455 if( DBG_IOBUF )
mpi-genesis 456 log_debug("%s: close fd %d\n", a->fname, fileno(f) );
mpi-genesis 457 if (!a->keep_open)
mpi-genesis 458 fclose(f);
mpi-genesis 459 }
mpi-genesis 460 f = NULL;
mpi-genesis 461 xfree(a); /* we can free our context now */
mpi-genesis 462 }
mpi-genesis 463 #else /* !stdio implementation */
mpi-genesis 464
mpi-genesis 465 if( control == IOBUFCTRL_UNDERFLOW ) {
mpi-genesis 466 assert( size ); /* need a buffer */
mpi-genesis 467 if ( a->eof_seen) {
mpi-genesis 468 rc = -1;
mpi-genesis 469 *ret_len = 0;
mpi-genesis 470 }
mpi-genesis 471 else {
mpi-genesis 472 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 473 unsigned long nread;
mpi-genesis 474
mpi-genesis 475 nbytes = 0;
mpi-genesis 476 if ( !ReadFile ( f, buf, size, &nread, NULL ) ) {
mpi-genesis 477 if ((int)GetLastError () != ERROR_BROKEN_PIPE) {
mpi-genesis 478 log_error ("%s: read error: %s\n", a->fname,
mpi-genesis 479 w32_strerror (0));
mpi-genesis 480 rc = G10ERR_READ_FILE;
mpi-genesis 481 }
mpi-genesis 482 }
mpi-genesis 483 else if ( !nread ) {
mpi-genesis 484 a->eof_seen = 1;
mpi-genesis 485 rc = -1;
mpi-genesis 486 }
mpi-genesis 487 else {
mpi-genesis 488 nbytes = nread;
mpi-genesis 489 }
mpi-genesis 490
mpi-genesis 491 #else
mpi-genesis 492
mpi-genesis 493 int n;
mpi-genesis 494
mpi-genesis 495 nbytes = 0;
mpi-genesis 496 do {
mpi-genesis 497 n = read ( f, buf, size );
mpi-genesis 498 } while (n == -1 && errno == EINTR );
mpi-genesis 499 if ( n == -1 ) { /* error */
mpi-genesis 500 if (errno != EPIPE) {
mpi-genesis 501 log_error("%s: read error: %s\n",
mpi-genesis 502 a->fname, strerror(errno));
mpi-genesis 503 rc = G10ERR_READ_FILE;
mpi-genesis 504 }
mpi-genesis 505 }
mpi-genesis 506 else if ( !n ) { /* eof */
mpi-genesis 507 a->eof_seen = 1;
mpi-genesis 508 rc = -1;
mpi-genesis 509 }
mpi-genesis 510 else {
mpi-genesis 511 nbytes = n;
mpi-genesis 512 }
mpi-genesis 513 #endif
mpi-genesis 514 *ret_len = nbytes;
mpi-genesis 515 }
mpi-genesis 516 }
mpi-genesis 517 else if( control == IOBUFCTRL_FLUSH ) {
mpi-genesis 518 if( size ) {
mpi-genesis 519 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 520 byte *p = buf;
mpi-genesis 521 unsigned long n;
mpi-genesis 522
mpi-genesis 523 nbytes = size;
mpi-genesis 524 do {
mpi-genesis 525 if (size && !WriteFile (f, p, nbytes, &n, NULL)) {
mpi-genesis 526 log_error ("%s: write error: %s\n", a->fname,
mpi-genesis 527 w32_strerror (0));
mpi-genesis 528 rc = G10ERR_WRITE_FILE;
mpi-genesis 529 break;
mpi-genesis 530 }
mpi-genesis 531 p += n;
mpi-genesis 532 nbytes -= n;
mpi-genesis 533 } while ( nbytes );
mpi-genesis 534 nbytes = p - buf;
mpi-genesis 535 #else
mpi-genesis 536 byte *p = buf;
mpi-genesis 537 int n;
mpi-genesis 538
mpi-genesis 539 nbytes = size;
mpi-genesis 540 do {
mpi-genesis 541 do {
mpi-genesis 542 n = write ( f, p, nbytes );
mpi-genesis 543 } while ( n == -1 && errno == EINTR );
mpi-genesis 544 if ( n > 0 ) {
mpi-genesis 545 p += n;
mpi-genesis 546 nbytes -= n;
mpi-genesis 547 }
mpi-genesis 548 } while ( n != -1 && nbytes );
mpi-genesis 549 if( n == -1 ) {
mpi-genesis 550 log_error("%s: write error: %s\n", a->fname, strerror(errno));
mpi-genesis 551 rc = G10ERR_WRITE_FILE;
mpi-genesis 552 }
mpi-genesis 553 nbytes = p - buf;
mpi-genesis 554 #endif
mpi-genesis 555 }
mpi-genesis 556 *ret_len = nbytes;
mpi-genesis 557 }
mpi-genesis 558 else if ( control == IOBUFCTRL_INIT ) {
mpi-genesis 559 a->eof_seen = 0;
mpi-genesis 560 a->keep_open = 0;
mpi-genesis 561 a->no_cache = 0;
mpi-genesis 562 }
mpi-genesis 563 else if ( control == IOBUFCTRL_DESC ) {
mpi-genesis 564 *(char**)buf = "file_filter(fd)";
mpi-genesis 565 }
mpi-genesis 566 else if ( control == IOBUFCTRL_FREE ) {
mpi-genesis 567 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 568 if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) {
mpi-genesis 569 if( DBG_IOBUF )
mpi-genesis 570 log_debug("%s: close handle %p\n", a->fname, f );
mpi-genesis 571 if (!a->keep_open)
mpi-genesis 572 fd_cache_close (a->no_cache?NULL:a->fname, f);
mpi-genesis 573 }
mpi-genesis 574 #else
mpi-genesis 575 if ( (int)f != 0 && (int)f != 1 ) {
mpi-genesis 576 if( DBG_IOBUF )
mpi-genesis 577 log_debug("%s: close fd %d\n", a->fname, f );
mpi-genesis 578 if (!a->keep_open)
mpi-genesis 579 fd_cache_close (a->no_cache?NULL:a->fname, f);
mpi-genesis 580 }
mpi-genesis 581 f = INVALID_FP;
mpi-genesis 582 #endif
mpi-genesis 583 xfree (a); /* we can free our context now */
mpi-genesis 584 }
mpi-genesis 585 #endif /* !stdio implementation */
mpi-genesis 586 return rc;
mpi-genesis 587 }
mpi-genesis 588
mpi-genesis 589 #ifdef _WIN32
mpi-genesis 590 /* Becuase sockets are an special object under Lose32 we have to
mpi-genesis 591 * use a special filter */
mpi-genesis 592 static int
mpi-genesis 593 sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
mpi-genesis 594 {
mpi-genesis 595 sock_filter_ctx_t *a = opaque;
mpi-genesis 596 size_t size = *ret_len;
mpi-genesis 597 size_t nbytes = 0;
mpi-genesis 598 int rc = 0;
mpi-genesis 599
mpi-genesis 600 if( control == IOBUFCTRL_UNDERFLOW ) {
mpi-genesis 601 assert( size ); /* need a buffer */
mpi-genesis 602 if ( a->eof_seen) {
mpi-genesis 603 rc = -1;
mpi-genesis 604 *ret_len = 0;
mpi-genesis 605 }
mpi-genesis 606 else {
mpi-genesis 607 int nread;
mpi-genesis 608
mpi-genesis 609 nread = recv ( a->sock, buf, size, 0 );
mpi-genesis 610 if ( nread == SOCKET_ERROR ) {
mpi-genesis 611 int ec = (int)WSAGetLastError ();
mpi-genesis 612 log_error("socket read error: ec=%d\n", ec);
mpi-genesis 613 rc = G10ERR_READ_FILE;
mpi-genesis 614 }
mpi-genesis 615 else if ( !nread ) {
mpi-genesis 616 a->eof_seen = 1;
mpi-genesis 617 rc = -1;
mpi-genesis 618 }
mpi-genesis 619 else {
mpi-genesis 620 nbytes = nread;
mpi-genesis 621 }
mpi-genesis 622 *ret_len = nbytes;
mpi-genesis 623 }
mpi-genesis 624 }
mpi-genesis 625 else if( control == IOBUFCTRL_FLUSH ) {
mpi-genesis 626 if( size ) {
mpi-genesis 627 byte *p = buf;
mpi-genesis 628 int n;
mpi-genesis 629
mpi-genesis 630 nbytes = size;
mpi-genesis 631 do {
mpi-genesis 632 n = send (a->sock, p, nbytes, 0);
mpi-genesis 633 if ( n == SOCKET_ERROR ) {
mpi-genesis 634 int ec = (int)WSAGetLastError ();
mpi-genesis 635 log_error("socket write error: ec=%d\n", ec);
mpi-genesis 636 rc = G10ERR_WRITE_FILE;
mpi-genesis 637 break;
mpi-genesis 638 }
mpi-genesis 639 p += n;
mpi-genesis 640 nbytes -= n;
mpi-genesis 641 } while ( nbytes );
mpi-genesis 642 nbytes = p - buf;
mpi-genesis 643 }
mpi-genesis 644 *ret_len = nbytes;
mpi-genesis 645 }
mpi-genesis 646 else if ( control == IOBUFCTRL_INIT ) {
mpi-genesis 647 a->eof_seen = 0;
mpi-genesis 648 a->keep_open = 0;
mpi-genesis 649 a->no_cache = 0;
mpi-genesis 650 }
mpi-genesis 651 else if ( control == IOBUFCTRL_DESC ) {
mpi-genesis 652 *(char**)buf = "sock_filter";
mpi-genesis 653 }
mpi-genesis 654 else if ( control == IOBUFCTRL_FREE ) {
mpi-genesis 655 if (!a->keep_open)
mpi-genesis 656 closesocket (a->sock);
mpi-genesis 657 xfree (a); /* we can free our context now */
mpi-genesis 658 }
mpi-genesis 659 return rc;
mpi-genesis 660 }
mpi-genesis 661 #endif /*_WIN32*/
mpi-genesis 662
mpi-genesis 663 /****************
mpi-genesis 664 * This is used to implement the block write mode.
mpi-genesis 665 * Block reading is done on a byte by byte basis in readbyte(),
mpi-genesis 666 * without a filter
mpi-genesis 667 */
mpi-genesis 668 static int
mpi-genesis 669 block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
mpi-genesis 670 {
mpi-genesis 671 block_filter_ctx_t *a = opaque;
mpi-genesis 672 size_t size = *ret_len;
mpi-genesis 673 int c, needed, rc = 0;
mpi-genesis 674 char *p;
mpi-genesis 675
mpi-genesis 676 if( control == IOBUFCTRL_UNDERFLOW ) {
mpi-genesis 677 size_t n=0;
mpi-genesis 678
mpi-genesis 679 p = buf;
mpi-genesis 680 assert( size ); /* need a buffer */
mpi-genesis 681 if( a->eof ) /* don't read any further */
mpi-genesis 682 rc = -1;
mpi-genesis 683 while( !rc && size ) {
mpi-genesis 684 if( !a->size ) { /* get the length bytes */
mpi-genesis 685 if( a->partial == 2 ) {
mpi-genesis 686 a->eof = 1;
mpi-genesis 687 if( !n )
mpi-genesis 688 rc = -1;
mpi-genesis 689 break;
mpi-genesis 690 }
mpi-genesis 691 else if( a->partial ) {
mpi-genesis 692 /* These OpenPGP introduced huffman like encoded length
mpi-genesis 693 * bytes are really a mess :-( */
mpi-genesis 694 if( a->first_c ) {
mpi-genesis 695 c = a->first_c;
mpi-genesis 696 a->first_c = 0;
mpi-genesis 697 }
mpi-genesis 698 else if( (c = iobuf_get(chain)) == -1 ) {
mpi-genesis 699 log_error("block_filter: 1st length byte missing\n");
mpi-genesis 700 rc = G10ERR_READ_FILE;
mpi-genesis 701 break;
mpi-genesis 702 }
mpi-genesis 703 if( c < 192 ) {
mpi-genesis 704 a->size = c;
mpi-genesis 705 a->partial = 2;
mpi-genesis 706 if( !a->size ) {
mpi-genesis 707 a->eof = 1;
mpi-genesis 708 if( !n )
mpi-genesis 709 rc = -1;
mpi-genesis 710 break;
mpi-genesis 711 }
mpi-genesis 712 }
mpi-genesis 713 else if( c < 224 ) {
mpi-genesis 714 a->size = (c - 192) * 256;
mpi-genesis 715 if( (c = iobuf_get(chain)) == -1 ) {
mpi-genesis 716 log_error("block_filter: 2nd length byte missing\n");
mpi-genesis 717 rc = G10ERR_READ_FILE;
mpi-genesis 718 break;
mpi-genesis 719 }
mpi-genesis 720 a->size += c + 192;
mpi-genesis 721 a->partial = 2;
mpi-genesis 722 if( !a->size ) {
mpi-genesis 723 a->eof = 1;
mpi-genesis 724 if( !n )
mpi-genesis 725 rc = -1;
mpi-genesis 726 break;
mpi-genesis 727 }
mpi-genesis 728 }
mpi-genesis 729 else if( c == 255 ) {
mpi-genesis 730 a->size = iobuf_get(chain) << 24;
mpi-genesis 731 a->size |= iobuf_get(chain) << 16;
mpi-genesis 732 a->size |= iobuf_get(chain) << 8;
mpi-genesis 733 if( (c = iobuf_get(chain)) == -1 ) {
mpi-genesis 734 log_error("block_filter: invalid 4 byte length\n");
mpi-genesis 735 rc = G10ERR_READ_FILE;
mpi-genesis 736 break;
mpi-genesis 737 }
mpi-genesis 738 a->size |= c;
mpi-genesis 739 a->partial = 2;
mpi-genesis 740 if( !a->size ) {
mpi-genesis 741 a->eof = 1;
mpi-genesis 742 if( !n )
mpi-genesis 743 rc = -1;
mpi-genesis 744 break;
mpi-genesis 745 }
mpi-genesis 746 }
mpi-genesis 747 else { /* next partial body length */
mpi-genesis 748 a->size = 1 << (c & 0x1f);
mpi-genesis 749 }
mpi-genesis 750 /* log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size);*/
mpi-genesis 751 }
mpi-genesis 752 else
mpi-genesis 753 BUG();
mpi-genesis 754 }
mpi-genesis 755
mpi-genesis 756 while( !rc && size && a->size ) {
mpi-genesis 757 needed = size < a->size ? size : a->size;
mpi-genesis 758 c = iobuf_read( chain, p, needed );
mpi-genesis 759 if( c < needed ) {
mpi-genesis 760 if( c == -1 ) c = 0;
mpi-genesis 761 log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
mpi-genesis 762 a, (ulong)size+c, (ulong)a->size+c);
mpi-genesis 763 rc = G10ERR_READ_FILE;
mpi-genesis 764 }
mpi-genesis 765 else {
mpi-genesis 766 size -= c;
mpi-genesis 767 a->size -= c;
mpi-genesis 768 p += c;
mpi-genesis 769 n += c;
mpi-genesis 770 }
mpi-genesis 771 }
mpi-genesis 772 }
mpi-genesis 773 *ret_len = n;
mpi-genesis 774 }
mpi-genesis 775 else if( control == IOBUFCTRL_FLUSH ) {
mpi-genesis 776 if( a->partial ) { /* the complicated openpgp scheme */
mpi-genesis 777 size_t blen, n, nbytes = size + a->buflen;
mpi-genesis 778
mpi-genesis 779 assert( a->buflen <= OP_MIN_PARTIAL_CHUNK );
mpi-genesis 780 if( nbytes < OP_MIN_PARTIAL_CHUNK ) {
mpi-genesis 781 /* not enough to write a partial block out; so we store it*/
mpi-genesis 782 if( !a->buffer )
mpi-genesis 783 a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK );
mpi-genesis 784 memcpy( a->buffer + a->buflen, buf, size );
mpi-genesis 785 a->buflen += size;
mpi-genesis 786 }
mpi-genesis 787 else { /* okay, we can write out something */
mpi-genesis 788 /* do this in a loop to use the most efficient block lengths */
mpi-genesis 789 p = buf;
mpi-genesis 790 do {
mpi-genesis 791 /* find the best matching block length - this is limited
mpi-genesis 792 * by the size of the internal buffering */
mpi-genesis 793 for( blen=OP_MIN_PARTIAL_CHUNK*2,
mpi-genesis 794 c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen <= nbytes;
mpi-genesis 795 blen *=2, c++ )
mpi-genesis 796 ;
mpi-genesis 797 blen /= 2; c--;
mpi-genesis 798 /* write the partial length header */
mpi-genesis 799 assert( c <= 0x1f ); /*;-)*/
mpi-genesis 800 c |= 0xe0;
mpi-genesis 801 iobuf_put( chain, c );
mpi-genesis 802 if( (n=a->buflen) ) { /* write stuff from the buffer */
mpi-genesis 803 assert( n == OP_MIN_PARTIAL_CHUNK);
mpi-genesis 804 if( iobuf_write(chain, a->buffer, n ) )
mpi-genesis 805 rc = G10ERR_WRITE_FILE;
mpi-genesis 806 a->buflen = 0;
mpi-genesis 807 nbytes -= n;
mpi-genesis 808 }
mpi-genesis 809 if( (n = nbytes) > blen )
mpi-genesis 810 n = blen;
mpi-genesis 811 if( n && iobuf_write(chain, p, n ) )
mpi-genesis 812 rc = G10ERR_WRITE_FILE;
mpi-genesis 813 p += n;
mpi-genesis 814 nbytes -= n;
mpi-genesis 815 } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK );
mpi-genesis 816 /* store the rest in the buffer */
mpi-genesis 817 if( !rc && nbytes ) {
mpi-genesis 818 assert( !a->buflen );
mpi-genesis 819 assert( nbytes < OP_MIN_PARTIAL_CHUNK );
mpi-genesis 820 if( !a->buffer )
mpi-genesis 821 a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK );
mpi-genesis 822 memcpy( a->buffer, p, nbytes );
mpi-genesis 823 a->buflen = nbytes;
mpi-genesis 824 }
mpi-genesis 825 }
mpi-genesis 826 }
mpi-genesis 827 else
mpi-genesis 828 BUG();
mpi-genesis 829 }
mpi-genesis 830 else if( control == IOBUFCTRL_INIT ) {
mpi-genesis 831 if( DBG_IOBUF )
mpi-genesis 832 log_debug("init block_filter %p\n", a );
mpi-genesis 833 if( a->partial )
mpi-genesis 834 a->count = 0;
mpi-genesis 835 else if( a->use == 1 )
mpi-genesis 836 a->count = a->size = 0;
mpi-genesis 837 else
mpi-genesis 838 a->count = a->size; /* force first length bytes */
mpi-genesis 839 a->eof = 0;
mpi-genesis 840 a->buffer = NULL;
mpi-genesis 841 a->buflen = 0;
mpi-genesis 842 }
mpi-genesis 843 else if( control == IOBUFCTRL_DESC ) {
mpi-genesis 844 *(char**)buf = "block_filter";
mpi-genesis 845 }
mpi-genesis 846 else if( control == IOBUFCTRL_FREE ) {
mpi-genesis 847 if( a->use == 2 ) { /* write the end markers */
mpi-genesis 848 if( a->partial ) {
mpi-genesis 849 u32 len;
mpi-genesis 850 /* write out the remaining bytes without a partial header
mpi-genesis 851 * the length of this header may be 0 - but if it is
mpi-genesis 852 * the first block we are not allowed to use a partial header
mpi-genesis 853 * and frankly we can't do so, because this length must be
mpi-genesis 854 * a power of 2. This is _really_ complicated because we
mpi-genesis 855 * have to check the possible length of a packet prior
mpi-genesis 856 * to it's creation: a chain of filters becomes complicated
mpi-genesis 857 * and we need a lot of code to handle compressed packets etc.
mpi-genesis 858 * :-(((((((
mpi-genesis 859 */
mpi-genesis 860 /* construct header */
mpi-genesis 861 len = a->buflen;
mpi-genesis 862 /*log_debug("partial: remaining length=%u\n", len );*/
mpi-genesis 863 if( len < 192 )
mpi-genesis 864 rc = iobuf_put(chain, len );
mpi-genesis 865 else if( len < 8384 ) {
mpi-genesis 866 if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) )
mpi-genesis 867 rc = iobuf_put( chain, ((len-192) % 256));
mpi-genesis 868 }
mpi-genesis 869 else { /* use a 4 byte header */
mpi-genesis 870 if( !(rc=iobuf_put( chain, 0xff )) )
mpi-genesis 871 if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) )
mpi-genesis 872 if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) )
mpi-genesis 873 if( !(rc=iobuf_put( chain, (len >> 8)&0xff )))
mpi-genesis 874 rc=iobuf_put( chain, len & 0xff );
mpi-genesis 875 }
mpi-genesis 876 if( !rc && len )
mpi-genesis 877 rc = iobuf_write(chain, a->buffer, len );
mpi-genesis 878 if( rc ) {
mpi-genesis 879 log_error("block_filter: write error: %s\n",strerror(errno));
mpi-genesis 880 rc = G10ERR_WRITE_FILE;
mpi-genesis 881 }
mpi-genesis 882 xfree( a->buffer ); a->buffer = NULL; a->buflen = 0;
mpi-genesis 883 }
mpi-genesis 884 else
mpi-genesis 885 BUG();
mpi-genesis 886 }
mpi-genesis 887 else if( a->size ) {
mpi-genesis 888 log_error("block_filter: pending bytes!\n");
mpi-genesis 889 }
mpi-genesis 890 if( DBG_IOBUF )
mpi-genesis 891 log_debug("free block_filter %p\n", a );
mpi-genesis 892 xfree(a); /* we can free our context now */
mpi-genesis 893 }
mpi-genesis 894
mpi-genesis 895 return rc;
mpi-genesis 896 }
mpi-genesis 897
mpi-genesis 898
mpi-genesis 899 static void
mpi-genesis 900 print_chain( IOBUF a )
mpi-genesis 901 {
mpi-genesis 902 if( !DBG_IOBUF )
mpi-genesis 903 return;
mpi-genesis 904 for(; a; a = a->chain ) {
mpi-genesis 905 size_t dummy_len = 0;
mpi-genesis 906 const char *desc = "[none]";
mpi-genesis 907
mpi-genesis 908 if( a->filter )
mpi-genesis 909 a->filter( a->filter_ov, IOBUFCTRL_DESC, NULL,
mpi-genesis 910 (byte*)&desc, &dummy_len );
mpi-genesis 911
mpi-genesis 912 log_debug("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
mpi-genesis 913 a->no, a->subno, desc?desc:"?", a->filter_eof,
mpi-genesis 914 (int)a->d.start, (int)a->d.len );
mpi-genesis 915 }
mpi-genesis 916 }
mpi-genesis 917
mpi-genesis 918 int
mpi-genesis 919 iobuf_print_chain( IOBUF a )
mpi-genesis 920 {
mpi-genesis 921 print_chain(a);
mpi-genesis 922 return 0;
mpi-genesis 923 }
mpi-genesis 924
mpi-genesis 925 /****************
mpi-genesis 926 * Allocate a new io buffer, with no function assigned.
mpi-genesis 927 * Use is the desired usage: 1 for input, 2 for output, 3 for temp buffer
mpi-genesis 928 * BUFSIZE is a suggested buffer size.
mpi-genesis 929 */
mpi-genesis 930 IOBUF
mpi-genesis 931 iobuf_alloc(int use, size_t bufsize)
mpi-genesis 932 {
mpi-genesis 933 IOBUF a;
mpi-genesis 934 static int number=0;
mpi-genesis 935
mpi-genesis 936 a = xmalloc_clear(sizeof *a);
mpi-genesis 937 a->use = use;
mpi-genesis 938 a->d.buf = xmalloc( bufsize );
mpi-genesis 939 a->d.size = bufsize;
mpi-genesis 940 a->no = ++number;
mpi-genesis 941 a->subno = 0;
mpi-genesis 942 a->opaque = NULL;
mpi-genesis 943 a->real_fname = NULL;
mpi-genesis 944 return a;
mpi-genesis 945 }
mpi-genesis 946
mpi-genesis 947 int
mpi-genesis 948 iobuf_close ( IOBUF a )
mpi-genesis 949 {
mpi-genesis 950 IOBUF a2;
mpi-genesis 951 size_t dummy_len=0;
mpi-genesis 952 int rc=0;
mpi-genesis 953
mpi-genesis 954 if( a && a->directfp ) {
mpi-genesis 955 fclose( a->directfp );
mpi-genesis 956 xfree( a->real_fname );
mpi-genesis 957 if( DBG_IOBUF )
mpi-genesis 958 log_debug("iobuf_close -> %p\n", a->directfp );
mpi-genesis 959 return 0;
mpi-genesis 960 }
mpi-genesis 961
mpi-genesis 962 for( ; a && !rc ; a = a2 ) {
mpi-genesis 963 a2 = a->chain;
mpi-genesis 964 if( a->use == 2 && (rc=iobuf_flush(a)) )
mpi-genesis 965 log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
mpi-genesis 966
mpi-genesis 967 if( DBG_IOBUF )
mpi-genesis 968 log_debug("iobuf-%d.%d: close `%s'\n", a->no, a->subno,
mpi-genesis 969 a->desc?a->desc:"?");
mpi-genesis 970 if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
mpi-genesis 971 a->chain, NULL, &dummy_len)) )
mpi-genesis 972 log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) );
mpi-genesis 973 xfree(a->real_fname);
mpi-genesis 974 if (a->d.buf) {
mpi-genesis 975 memset (a->d.buf, 0, a->d.size); /* erase the buffer */
mpi-genesis 976 xfree(a->d.buf);
mpi-genesis 977 }
mpi-genesis 978 xfree(a);
mpi-genesis 979 }
mpi-genesis 980 return rc;
mpi-genesis 981 }
mpi-genesis 982
mpi-genesis 983 int
mpi-genesis 984 iobuf_cancel( IOBUF a )
mpi-genesis 985 {
mpi-genesis 986 const char *s;
mpi-genesis 987 IOBUF a2;
mpi-genesis 988 int rc;
mpi-genesis 989 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
mpi-genesis 990 char *remove_name = NULL;
mpi-genesis 991 #endif
mpi-genesis 992
mpi-genesis 993 if( a && a->use == 2 ) {
mpi-genesis 994 s = iobuf_get_real_fname(a);
mpi-genesis 995 if( s && *s ) {
mpi-genesis 996 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
mpi-genesis 997 remove_name = xstrdup ( s );
mpi-genesis 998 #else
mpi-genesis 999 remove(s);
mpi-genesis 1000 #endif
mpi-genesis 1001 }
mpi-genesis 1002 }
mpi-genesis 1003
mpi-genesis 1004 /* send a cancel message to all filters */
mpi-genesis 1005 for( a2 = a; a2 ; a2 = a2->chain ) {
mpi-genesis 1006 size_t dummy;
mpi-genesis 1007 if( a2->filter )
mpi-genesis 1008 a2->filter( a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain,
mpi-genesis 1009 NULL, &dummy );
mpi-genesis 1010 }
mpi-genesis 1011
mpi-genesis 1012 rc = iobuf_close(a);
mpi-genesis 1013 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
mpi-genesis 1014 if ( remove_name ) {
mpi-genesis 1015 /* Argg, MSDOS does not allow to remove open files. So
mpi-genesis 1016 * we have to do it here */
mpi-genesis 1017 remove ( remove_name );
mpi-genesis 1018 xfree ( remove_name );
mpi-genesis 1019 }
mpi-genesis 1020 #endif
mpi-genesis 1021 return rc;
mpi-genesis 1022 }
mpi-genesis 1023
mpi-genesis 1024
mpi-genesis 1025 /****************
mpi-genesis 1026 * create a temporary iobuf, which can be used to collect stuff
mpi-genesis 1027 * in an iobuf and later be written by iobuf_write_temp() to another
mpi-genesis 1028 * iobuf.
mpi-genesis 1029 */
mpi-genesis 1030 IOBUF
mpi-genesis 1031 iobuf_temp()
mpi-genesis 1032 {
mpi-genesis 1033 IOBUF a;
mpi-genesis 1034
mpi-genesis 1035 a = iobuf_alloc(3, IOBUF_BUFFER_SIZE );
mpi-genesis 1036
mpi-genesis 1037 return a;
mpi-genesis 1038 }
mpi-genesis 1039
mpi-genesis 1040 IOBUF
mpi-genesis 1041 iobuf_temp_with_content( const char *buffer, size_t length )
mpi-genesis 1042 {
mpi-genesis 1043 IOBUF a;
mpi-genesis 1044
mpi-genesis 1045 a = iobuf_alloc(3, length );
mpi-genesis 1046 memcpy( a->d.buf, buffer, length );
mpi-genesis 1047 a->d.len = length;
mpi-genesis 1048
mpi-genesis 1049 return a;
mpi-genesis 1050 }
mpi-genesis 1051
mpi-genesis 1052 void
mpi-genesis 1053 iobuf_enable_special_filenames ( int yes )
mpi-genesis 1054 {
mpi-genesis 1055 special_names_enabled = yes;
mpi-genesis 1056 }
mpi-genesis 1057
mpi-genesis 1058 /*
mpi-genesis 1059 * see whether the filename has the for "-&nnnn", where n is a
mpi-genesis 1060 * non-zero number.
mpi-genesis 1061 * Returns this number or -1 if it is not the case.
mpi-genesis 1062 */
mpi-genesis 1063 static int
mpi-genesis 1064 check_special_filename ( const char *fname )
mpi-genesis 1065 {
mpi-genesis 1066 if ( special_names_enabled
mpi-genesis 1067 && fname && *fname == '-' && fname[1] == '&' ) {
mpi-genesis 1068 int i;
mpi-genesis 1069
mpi-genesis 1070 fname += 2;
mpi-genesis 1071 for (i=0; digitp (fname+i); i++ )
mpi-genesis 1072 ;
mpi-genesis 1073 if ( !fname[i] )
mpi-genesis 1074 return atoi (fname);
mpi-genesis 1075 }
mpi-genesis 1076 return -1;
mpi-genesis 1077 }
mpi-genesis 1078
mpi-genesis 1079 /* This fucntion returns true if FNAME indicates a PIPE (stdout or
mpi-genesis 1080 stderr) or a special file name if those are enabled. */
mpi-genesis 1081 int
mpi-genesis 1082 iobuf_is_pipe_filename (const char *fname)
mpi-genesis 1083 {
mpi-genesis 1084 if (!fname || (*fname=='-' && !fname[1]) )
mpi-genesis 1085 return 1;
mpi-genesis 1086 return check_special_filename (fname) != -1;
mpi-genesis 1087 }
mpi-genesis 1088
mpi-genesis 1089 /****************
mpi-genesis 1090 * Create a head iobuf for reading from a file
mpi-genesis 1091 * returns: NULL if an error occures and sets errno
mpi-genesis 1092 */
mpi-genesis 1093 IOBUF
mpi-genesis 1094 iobuf_open( const char *fname )
mpi-genesis 1095 {
mpi-genesis 1096 IOBUF a;
mpi-genesis 1097 FILEP_OR_FD fp;
mpi-genesis 1098 file_filter_ctx_t *fcx;
mpi-genesis 1099 size_t len;
mpi-genesis 1100 int print_only = 0;
mpi-genesis 1101 int fd;
mpi-genesis 1102
mpi-genesis 1103 if( !fname || (*fname=='-' && !fname[1]) ) {
mpi-genesis 1104 fp = FILEP_OR_FD_FOR_STDIN;
mpi-genesis 1105 #ifdef USE_SETMODE
mpi-genesis 1106 setmode ( my_fileno(fp) , O_BINARY );
mpi-genesis 1107 #endif
mpi-genesis 1108 fname = "[stdin]";
mpi-genesis 1109 print_only = 1;
mpi-genesis 1110 }
mpi-genesis 1111 else if ( (fd = check_special_filename ( fname )) != -1 )
mpi-genesis 1112 return iobuf_fdopen ( translate_file_handle (fd,0), "rb" );
mpi-genesis 1113 else if( (fp = my_fopen_ro(fname, "rb")) == INVALID_FP )
mpi-genesis 1114 return NULL;
mpi-genesis 1115 a = iobuf_alloc(1, IOBUF_BUFFER_SIZE );
mpi-genesis 1116 fcx = xmalloc( sizeof *fcx + strlen(fname) );
mpi-genesis 1117 fcx->fp = fp;
mpi-genesis 1118 fcx->print_only_name = print_only;
mpi-genesis 1119 strcpy(fcx->fname, fname );
mpi-genesis 1120 if( !print_only )
mpi-genesis 1121 a->real_fname = xstrdup( fname );
mpi-genesis 1122 a->filter = file_filter;
mpi-genesis 1123 a->filter_ov = fcx;
mpi-genesis 1124 file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1125 file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1126 if( DBG_IOBUF )
mpi-genesis 1127 log_debug("iobuf-%d.%d: open `%s' fd=%d\n",
mpi-genesis 1128 a->no, a->subno, fname, (int)my_fileno(fcx->fp) );
mpi-genesis 1129
mpi-genesis 1130 return a;
mpi-genesis 1131 }
mpi-genesis 1132
mpi-genesis 1133 /****************
mpi-genesis 1134 * Create a head iobuf for reading from a file
mpi-genesis 1135 * returns: NULL if an error occures and sets errno
mpi-genesis 1136 */
mpi-genesis 1137 IOBUF
mpi-genesis 1138 iobuf_fdopen( int fd, const char *mode )
mpi-genesis 1139 {
mpi-genesis 1140 IOBUF a;
mpi-genesis 1141 FILEP_OR_FD fp;
mpi-genesis 1142 file_filter_ctx_t *fcx;
mpi-genesis 1143 size_t len;
mpi-genesis 1144
mpi-genesis 1145 #ifdef FILE_FILTER_USES_STDIO
mpi-genesis 1146 if( !(fp = fdopen(fd, mode)) )
mpi-genesis 1147 return NULL;
mpi-genesis 1148 #else
mpi-genesis 1149 fp = (FILEP_OR_FD)fd;
mpi-genesis 1150 #endif
mpi-genesis 1151 a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE );
mpi-genesis 1152 fcx = xmalloc( sizeof *fcx + 20 );
mpi-genesis 1153 fcx->fp = fp;
mpi-genesis 1154 fcx->print_only_name = 1;
mpi-genesis 1155 sprintf(fcx->fname, "[fd %d]", fd );
mpi-genesis 1156 a->filter = file_filter;
mpi-genesis 1157 a->filter_ov = fcx;
mpi-genesis 1158 file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1159 file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1160 if( DBG_IOBUF )
mpi-genesis 1161 log_debug("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname );
mpi-genesis 1162 iobuf_ioctl (a,3,1,NULL); /* disable fd caching */
mpi-genesis 1163 return a;
mpi-genesis 1164 }
mpi-genesis 1165
mpi-genesis 1166
mpi-genesis 1167 IOBUF
mpi-genesis 1168 iobuf_sockopen ( int fd, const char *mode )
mpi-genesis 1169 {
mpi-genesis 1170 IOBUF a;
mpi-genesis 1171 #ifdef _WIN32
mpi-genesis 1172 sock_filter_ctx_t *scx;
mpi-genesis 1173 size_t len;
mpi-genesis 1174
mpi-genesis 1175 a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE );
mpi-genesis 1176 scx = xmalloc( sizeof *scx + 25 );
mpi-genesis 1177 scx->sock = fd;
mpi-genesis 1178 scx->print_only_name = 1;
mpi-genesis 1179 sprintf(scx->fname, "[sock %d]", fd );
mpi-genesis 1180 a->filter = sock_filter;
mpi-genesis 1181 a->filter_ov = scx;
mpi-genesis 1182 sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1183 sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1184 if( DBG_IOBUF )
mpi-genesis 1185 log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname);
mpi-genesis 1186 iobuf_ioctl (a,3,1,NULL); /* disable fd caching */
mpi-genesis 1187 #else
mpi-genesis 1188 a = iobuf_fdopen (fd, mode);
mpi-genesis 1189 #endif
mpi-genesis 1190 return a;
mpi-genesis 1191 }
mpi-genesis 1192
mpi-genesis 1193 /****************
mpi-genesis 1194 * create an iobuf for writing to a file; the file will be created.
mpi-genesis 1195 */
mpi-genesis 1196 IOBUF
mpi-genesis 1197 iobuf_create( const char *fname )
mpi-genesis 1198 {
mpi-genesis 1199 IOBUF a;
mpi-genesis 1200 FILEP_OR_FD fp;
mpi-genesis 1201 file_filter_ctx_t *fcx;
mpi-genesis 1202 size_t len;
mpi-genesis 1203 int print_only = 0;
mpi-genesis 1204 int fd;
mpi-genesis 1205
mpi-genesis 1206 if( !fname || (*fname=='-' && !fname[1]) ) {
mpi-genesis 1207 fp = FILEP_OR_FD_FOR_STDOUT;
mpi-genesis 1208 #ifdef USE_SETMODE
mpi-genesis 1209 setmode ( my_fileno(fp) , O_BINARY );
mpi-genesis 1210 #endif
mpi-genesis 1211 fname = "[stdout]";
mpi-genesis 1212 print_only = 1;
mpi-genesis 1213 }
mpi-genesis 1214 else if ( (fd = check_special_filename ( fname )) != -1 )
mpi-genesis 1215 return iobuf_fdopen ( translate_file_handle (fd, 1), "wb" );
mpi-genesis 1216 else if( (fp = my_fopen(fname, "wb")) == INVALID_FP )
mpi-genesis 1217 return NULL;
mpi-genesis 1218 a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
mpi-genesis 1219 fcx = xmalloc( sizeof *fcx + strlen(fname) );
mpi-genesis 1220 fcx->fp = fp;
mpi-genesis 1221 fcx->print_only_name = print_only;
mpi-genesis 1222 strcpy(fcx->fname, fname );
mpi-genesis 1223 if( !print_only )
mpi-genesis 1224 a->real_fname = xstrdup( fname );
mpi-genesis 1225 a->filter = file_filter;
mpi-genesis 1226 a->filter_ov = fcx;
mpi-genesis 1227 file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1228 file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1229 if( DBG_IOBUF )
mpi-genesis 1230 log_debug("iobuf-%d.%d: create `%s'\n", a->no, a->subno,
mpi-genesis 1231 a->desc?a->desc:"?" );
mpi-genesis 1232
mpi-genesis 1233 return a;
mpi-genesis 1234 }
mpi-genesis 1235
mpi-genesis 1236 /****************
mpi-genesis 1237 * append to an iobuf; if the file does not exist, create it.
mpi-genesis 1238 * cannot be used for stdout.
mpi-genesis 1239 * Note: This is not used.
mpi-genesis 1240 */
mpi-genesis 1241 #if 0 /* not used */
mpi-genesis 1242 IOBUF
mpi-genesis 1243 iobuf_append( const char *fname )
mpi-genesis 1244 {
mpi-genesis 1245 IOBUF a;
mpi-genesis 1246 FILE *fp;
mpi-genesis 1247 file_filter_ctx_t *fcx;
mpi-genesis 1248 size_t len;
mpi-genesis 1249
mpi-genesis 1250 if( !fname )
mpi-genesis 1251 return NULL;
mpi-genesis 1252 else if( !(fp = my_fopen(fname, "ab")) )
mpi-genesis 1253 return NULL;
mpi-genesis 1254 a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
mpi-genesis 1255 fcx = xmalloc( sizeof *fcx + strlen(fname) );
mpi-genesis 1256 fcx->fp = fp;
mpi-genesis 1257 strcpy(fcx->fname, fname );
mpi-genesis 1258 a->real_fname = xstrdup( fname );
mpi-genesis 1259 a->filter = file_filter;
mpi-genesis 1260 a->filter_ov = fcx;
mpi-genesis 1261 file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1262 file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1263 if( DBG_IOBUF )
mpi-genesis 1264 log_debug("iobuf-%d.%d: append `%s'\n", a->no, a->subno,
mpi-genesis 1265 a->desc?a->desc:"?" );
mpi-genesis 1266
mpi-genesis 1267 return a;
mpi-genesis 1268 }
mpi-genesis 1269 #endif
mpi-genesis 1270
mpi-genesis 1271 IOBUF
mpi-genesis 1272 iobuf_openrw( const char *fname )
mpi-genesis 1273 {
mpi-genesis 1274 IOBUF a;
mpi-genesis 1275 FILEP_OR_FD fp;
mpi-genesis 1276 file_filter_ctx_t *fcx;
mpi-genesis 1277 size_t len;
mpi-genesis 1278
mpi-genesis 1279 if( !fname )
mpi-genesis 1280 return NULL;
mpi-genesis 1281 else if( (fp = my_fopen(fname, "r+b")) == INVALID_FP )
mpi-genesis 1282 return NULL;
mpi-genesis 1283 a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
mpi-genesis 1284 fcx = xmalloc( sizeof *fcx + strlen(fname) );
mpi-genesis 1285 fcx->fp = fp;
mpi-genesis 1286 strcpy(fcx->fname, fname );
mpi-genesis 1287 a->real_fname = xstrdup( fname );
mpi-genesis 1288 a->filter = file_filter;
mpi-genesis 1289 a->filter_ov = fcx;
mpi-genesis 1290 file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
mpi-genesis 1291 file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
mpi-genesis 1292 if( DBG_IOBUF )
mpi-genesis 1293 log_debug("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno,
mpi-genesis 1294 a->desc?a->desc:"?");
mpi-genesis 1295
mpi-genesis 1296 return a;
mpi-genesis 1297 }
mpi-genesis 1298
mpi-genesis 1299
mpi-genesis 1300 int
mpi-genesis 1301 iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval )
mpi-genesis 1302 {
mpi-genesis 1303 if ( cmd == 1 ) { /* keep system filepointer/descriptor open */
mpi-genesis 1304 if( DBG_IOBUF )
mpi-genesis 1305 log_debug("iobuf-%d.%d: ioctl `%s' keep=%d\n",
mpi-genesis 1306 a? a->no:-1, a?a->subno:-1,
mpi-genesis 1307 a&&a->desc?a->desc:"?", intval );
mpi-genesis 1308 for( ; a; a = a->chain )
mpi-genesis 1309 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 1310 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 1311 b->keep_open = intval;
mpi-genesis 1312 return 0;
mpi-genesis 1313 }
mpi-genesis 1314 #ifdef _WIN32
mpi-genesis 1315 else if( !a->chain && a->filter == sock_filter ) {
mpi-genesis 1316 sock_filter_ctx_t *b = a->filter_ov;
mpi-genesis 1317 b->keep_open = intval;
mpi-genesis 1318 return 0;
mpi-genesis 1319 }
mpi-genesis 1320 #endif
mpi-genesis 1321 }
mpi-genesis 1322 else if ( cmd == 2 ) { /* invalidate cache */
mpi-genesis 1323 if( DBG_IOBUF )
mpi-genesis 1324 log_debug("iobuf-*.*: ioctl `%s' invalidate\n",
mpi-genesis 1325 ptrval? (char*)ptrval:"[all]");
mpi-genesis 1326 if ( !a && !intval ) {
mpi-genesis 1327 #ifndef FILE_FILTER_USES_STDIO
mpi-genesis 1328 return fd_cache_invalidate (ptrval);
mpi-genesis 1329 #endif
mpi-genesis 1330 return 0;
mpi-genesis 1331 }
mpi-genesis 1332 }
mpi-genesis 1333 else if ( cmd == 3 ) { /* disallow/allow caching */
mpi-genesis 1334 if( DBG_IOBUF )
mpi-genesis 1335 log_debug("iobuf-%d.%d: ioctl `%s' no_cache=%d\n",
mpi-genesis 1336 a? a->no:-1, a?a->subno:-1,
mpi-genesis 1337 a&&a->desc?a->desc:"?", intval );
mpi-genesis 1338 for( ; a; a = a->chain )
mpi-genesis 1339 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 1340 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 1341 b->no_cache = intval;
mpi-genesis 1342 return 0;
mpi-genesis 1343 }
mpi-genesis 1344 #ifdef _WIN32
mpi-genesis 1345 else if( !a->chain && a->filter == sock_filter ) {
mpi-genesis 1346 sock_filter_ctx_t *b = a->filter_ov;
mpi-genesis 1347 b->no_cache = intval;
mpi-genesis 1348 return 0;
mpi-genesis 1349 }
mpi-genesis 1350 #endif
mpi-genesis 1351 }
mpi-genesis 1352 else if(cmd==4)
mpi-genesis 1353 {
mpi-genesis 1354 /* Do a fsync on the open fd and return any errors to the
mpi-genesis 1355 caller of iobuf_ioctl */
mpi-genesis 1356 if( DBG_IOBUF )
mpi-genesis 1357 log_debug("iobuf-*.*: ioctl `%s' fsync\n",
mpi-genesis 1358 ptrval? (char*)ptrval:"<null>");
mpi-genesis 1359
mpi-genesis 1360 if(!a && !intval && ptrval)
mpi-genesis 1361 {
mpi-genesis 1362 #ifndef FILE_FILTER_USES_STDIO
mpi-genesis 1363 return fd_cache_synchronize (ptrval);
mpi-genesis 1364 #else
mpi-genesis 1365 return 0;
mpi-genesis 1366 #endif
mpi-genesis 1367 }
mpi-genesis 1368 }
mpi-genesis 1369
mpi-genesis 1370 return -1;
mpi-genesis 1371 }
mpi-genesis 1372
mpi-genesis 1373
mpi-genesis 1374 /****************
mpi-genesis 1375 * Register an i/o filter.
mpi-genesis 1376 */
mpi-genesis 1377 int
mpi-genesis 1378 iobuf_push_filter( IOBUF a,
mpi-genesis 1379 int (*f)(void *opaque, int control,
mpi-genesis 1380 IOBUF chain, byte *buf, size_t *len), void *ov )
mpi-genesis 1381 {
mpi-genesis 1382 return iobuf_push_filter2( a, f, ov, 0 );
mpi-genesis 1383 }
mpi-genesis 1384
mpi-genesis 1385 int
mpi-genesis 1386 iobuf_push_filter2( IOBUF a,
mpi-genesis 1387 int (*f)(void *opaque, int control,
mpi-genesis 1388 IOBUF chain, byte *buf, size_t *len),
mpi-genesis 1389 void *ov, int rel_ov )
mpi-genesis 1390 {
mpi-genesis 1391 IOBUF b;
mpi-genesis 1392 size_t dummy_len=0;
mpi-genesis 1393 int rc=0;
mpi-genesis 1394
mpi-genesis 1395 if( a->directfp )
mpi-genesis 1396 BUG();
mpi-genesis 1397
mpi-genesis 1398 if( a->use == 2 && (rc=iobuf_flush(a)) )
mpi-genesis 1399 return rc;
mpi-genesis 1400 /* make a copy of the current stream, so that
mpi-genesis 1401 * A is the new stream and B the original one.
mpi-genesis 1402 * The contents of the buffers are transferred to the
mpi-genesis 1403 * new stream.
mpi-genesis 1404 */
mpi-genesis 1405 b = xmalloc(sizeof *b);
mpi-genesis 1406 memcpy(b, a, sizeof *b );
mpi-genesis 1407 /* fixme: it is stupid to keep a copy of the name at every level
mpi-genesis 1408 * but we need the name somewhere because the name known by file_filter
mpi-genesis 1409 * may have been released when we need the name of the file */
mpi-genesis 1410 b->real_fname = a->real_fname? xstrdup(a->real_fname):NULL;
mpi-genesis 1411 /* remove the filter stuff from the new stream */
mpi-genesis 1412 a->filter = NULL;
mpi-genesis 1413 a->filter_ov = NULL;
mpi-genesis 1414 a->filter_ov_owner = 0;
mpi-genesis 1415 a->filter_eof = 0;
mpi-genesis 1416 if( a->use == 3 )
mpi-genesis 1417 a->use = 2; /* make a write stream from a temp stream */
mpi-genesis 1418
mpi-genesis 1419 if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */
mpi-genesis 1420 b->d.buf = xmalloc( a->d.size );
mpi-genesis 1421 b->d.len = 0;
mpi-genesis 1422 b->d.start = 0;
mpi-genesis 1423 }
mpi-genesis 1424 else { /* allocate a fresh buffer for the new stream */
mpi-genesis 1425 a->d.buf = xmalloc( a->d.size );
mpi-genesis 1426 a->d.len = 0;
mpi-genesis 1427 a->d.start = 0;
mpi-genesis 1428 }
mpi-genesis 1429 /* disable nlimit for the new stream */
mpi-genesis 1430 a->ntotal = b->ntotal + b->nbytes;
mpi-genesis 1431 a->nlimit = a->nbytes = 0;
mpi-genesis 1432 a->nofast &= ~1;
mpi-genesis 1433 /* make a link from the new stream to the original stream */
mpi-genesis 1434 a->chain = b;
mpi-genesis 1435 a->opaque = b->opaque;
mpi-genesis 1436
mpi-genesis 1437 /* setup the function on the new stream */
mpi-genesis 1438 a->filter = f;
mpi-genesis 1439 a->filter_ov = ov;
mpi-genesis 1440 a->filter_ov_owner = rel_ov;
mpi-genesis 1441
mpi-genesis 1442 a->subno = b->subno + 1;
mpi-genesis 1443 f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
mpi-genesis 1444
mpi-genesis 1445 if( DBG_IOBUF ) {
mpi-genesis 1446 log_debug("iobuf-%d.%d: push `%s'\n", a->no, a->subno,
mpi-genesis 1447 a->desc?a->desc:"?" );
mpi-genesis 1448 print_chain( a );
mpi-genesis 1449 }
mpi-genesis 1450
mpi-genesis 1451 /* now we can initialize the new function if we have one */
mpi-genesis 1452 if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
mpi-genesis 1453 NULL, &dummy_len)) )
mpi-genesis 1454 log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) );
mpi-genesis 1455 return rc;
mpi-genesis 1456 }
mpi-genesis 1457
mpi-genesis 1458 /****************
mpi-genesis 1459 * Remove an i/o filter.
mpi-genesis 1460 */
mpi-genesis 1461 static int
mpi-genesis 1462 pop_filter( IOBUF a, int (*f)(void *opaque, int control,
mpi-genesis 1463 IOBUF chain, byte *buf, size_t *len), void *ov )
mpi-genesis 1464 {
mpi-genesis 1465 IOBUF b;
mpi-genesis 1466 size_t dummy_len=0;
mpi-genesis 1467 int rc=0;
mpi-genesis 1468
mpi-genesis 1469 if( a->directfp )
mpi-genesis 1470 BUG();
mpi-genesis 1471
mpi-genesis 1472 if( DBG_IOBUF )
mpi-genesis 1473 log_debug("iobuf-%d.%d: pop `%s'\n", a->no, a->subno,
mpi-genesis 1474 a->desc?a->desc:"?" );
mpi-genesis 1475 if( !a->filter ) { /* this is simple */
mpi-genesis 1476 b = a->chain;
mpi-genesis 1477 assert(b);
mpi-genesis 1478 xfree(a->d.buf);
mpi-genesis 1479 xfree(a->real_fname);
mpi-genesis 1480 memcpy(a,b, sizeof *a);
mpi-genesis 1481 xfree(b);
mpi-genesis 1482 return 0;
mpi-genesis 1483 }
mpi-genesis 1484 for(b=a ; b; b = b->chain )
mpi-genesis 1485 if( b->filter == f && (!ov || b->filter_ov == ov) )
mpi-genesis 1486 break;
mpi-genesis 1487 if( !b )
mpi-genesis 1488 log_bug("pop_filter(): filter function not found\n");
mpi-genesis 1489
mpi-genesis 1490 /* flush this stream if it is an output stream */
mpi-genesis 1491 if( a->use == 2 && (rc=iobuf_flush(b)) ) {
mpi-genesis 1492 log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc));
mpi-genesis 1493 return rc;
mpi-genesis 1494 }
mpi-genesis 1495 /* and tell the filter to free it self */
mpi-genesis 1496 if( b->filter && (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
mpi-genesis 1497 NULL, &dummy_len)) ) {
mpi-genesis 1498 log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
mpi-genesis 1499 return rc;
mpi-genesis 1500 }
mpi-genesis 1501 if( b->filter_ov && b->filter_ov_owner ) {
mpi-genesis 1502 xfree( b->filter_ov );
mpi-genesis 1503 b->filter_ov = NULL;
mpi-genesis 1504 }
mpi-genesis 1505
mpi-genesis 1506
mpi-genesis 1507 /* and see how to remove it */
mpi-genesis 1508 if( a == b && !b->chain )
mpi-genesis 1509 log_bug("can't remove the last filter from the chain\n");
mpi-genesis 1510 else if( a == b ) { /* remove the first iobuf from the chain */
mpi-genesis 1511 /* everything from b is copied to a. This is save because
mpi-genesis 1512 * a flush has been done on the to be removed entry
mpi-genesis 1513 */
mpi-genesis 1514 b = a->chain;
mpi-genesis 1515 xfree(a->d.buf);
mpi-genesis 1516 xfree(a->real_fname);
mpi-genesis 1517 memcpy(a,b, sizeof *a);
mpi-genesis 1518 xfree(b);
mpi-genesis 1519 if( DBG_IOBUF )
mpi-genesis 1520 log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno );
mpi-genesis 1521 }
mpi-genesis 1522 else if( !b->chain ) { /* remove the last iobuf from the chain */
mpi-genesis 1523 log_bug("Ohh jeee, trying to remove a head filter\n");
mpi-genesis 1524 }
mpi-genesis 1525 else { /* remove an intermediate iobuf from the chain */
mpi-genesis 1526 log_bug("Ohh jeee, trying to remove an intermediate filter\n");
mpi-genesis 1527 }
mpi-genesis 1528
mpi-genesis 1529 return rc;
mpi-genesis 1530 }
mpi-genesis 1531
mpi-genesis 1532
mpi-genesis 1533 /****************
mpi-genesis 1534 * read underflow: read more bytes into the buffer and return
mpi-genesis 1535 * the first byte or -1 on EOF.
mpi-genesis 1536 */
mpi-genesis 1537 static int
mpi-genesis 1538 underflow(IOBUF a)
mpi-genesis 1539 {
mpi-genesis 1540 size_t len;
mpi-genesis 1541 int rc;
mpi-genesis 1542
mpi-genesis 1543 assert( a->d.start == a->d.len );
mpi-genesis 1544 if( a->use == 3 )
mpi-genesis 1545 return -1; /* EOF because a temp buffer can't do an underflow */
mpi-genesis 1546
mpi-genesis 1547 if( a->filter_eof ) {
mpi-genesis 1548 if( a->chain ) {
mpi-genesis 1549 IOBUF b = a->chain;
mpi-genesis 1550 if( DBG_IOBUF )
mpi-genesis 1551 log_debug("iobuf-%d.%d: pop `%s' in underflow\n",
mpi-genesis 1552 a->no, a->subno, a->desc?a->desc:"?" );
mpi-genesis 1553 xfree(a->d.buf);
mpi-genesis 1554 xfree(a->real_fname);
mpi-genesis 1555 memcpy(a, b, sizeof *a);
mpi-genesis 1556 xfree(b);
mpi-genesis 1557 print_chain(a);
mpi-genesis 1558 }
mpi-genesis 1559 else
mpi-genesis 1560 a->filter_eof = 0; /* for the top level filter */
mpi-genesis 1561 if( DBG_IOBUF )
mpi-genesis 1562 log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n",
mpi-genesis 1563 a->no, a->subno );
mpi-genesis 1564 return -1; /* return one(!) EOF */
mpi-genesis 1565 }
mpi-genesis 1566 if( a->error ) {
mpi-genesis 1567 if( DBG_IOBUF )
mpi-genesis 1568 log_debug("iobuf-%d.%d: error\n", a->no, a->subno );
mpi-genesis 1569 return -1;
mpi-genesis 1570 }
mpi-genesis 1571
mpi-genesis 1572 if( a->directfp ) {
mpi-genesis 1573 FILE *fp = a->directfp;
mpi-genesis 1574
mpi-genesis 1575 len = fread( a->d.buf, 1, a->d.size, fp);
mpi-genesis 1576 if( len < a->d.size ) {
mpi-genesis 1577 if( ferror(fp) )
mpi-genesis 1578 a->error = 1;
mpi-genesis 1579 }
mpi-genesis 1580 a->d.len = len;
mpi-genesis 1581 a->d.start = 0;
mpi-genesis 1582 return len? a->d.buf[a->d.start++] : -1;
mpi-genesis 1583 }
mpi-genesis 1584
mpi-genesis 1585
mpi-genesis 1586 if( a->filter ) {
mpi-genesis 1587 len = a->d.size;
mpi-genesis 1588 if( DBG_IOBUF )
mpi-genesis 1589 log_debug("iobuf-%d.%d: underflow: req=%lu\n",
mpi-genesis 1590 a->no, a->subno, (ulong)len );
mpi-genesis 1591 rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
mpi-genesis 1592 a->d.buf, &len );
mpi-genesis 1593 if( DBG_IOBUF ) {
mpi-genesis 1594 log_debug("iobuf-%d.%d: underflow: got=%lu rc=%d\n",
mpi-genesis 1595 a->no, a->subno, (ulong)len, rc );
mpi-genesis 1596 /* if( a->no == 1 ) */
mpi-genesis 1597 /* log_hexdump (" data:", a->d.buf, len); */
mpi-genesis 1598 }
mpi-genesis 1599 if( a->use == 1 && rc == -1 ) { /* EOF: we can remove the filter */
mpi-genesis 1600 size_t dummy_len=0;
mpi-genesis 1601
mpi-genesis 1602 /* and tell the filter to free itself */
mpi-genesis 1603 if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
mpi-genesis 1604 NULL, &dummy_len)) )
mpi-genesis 1605 log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
mpi-genesis 1606 if( a->filter_ov && a->filter_ov_owner ) {
mpi-genesis 1607 xfree( a->filter_ov );
mpi-genesis 1608 a->filter_ov = NULL;
mpi-genesis 1609 }
mpi-genesis 1610 a->filter = NULL;
mpi-genesis 1611 a->desc = NULL;
mpi-genesis 1612 a->filter_ov = NULL;
mpi-genesis 1613 a->filter_eof = 1;
mpi-genesis 1614 if( !len && a->chain ) {
mpi-genesis 1615 IOBUF b = a->chain;
mpi-genesis 1616 if( DBG_IOBUF )
mpi-genesis 1617 log_debug("iobuf-%d.%d: pop in underflow (!len)\n",
mpi-genesis 1618 a->no, a->subno);
mpi-genesis 1619 xfree(a->d.buf);
mpi-genesis 1620 xfree(a->real_fname);
mpi-genesis 1621 memcpy(a,b, sizeof *a);
mpi-genesis 1622 xfree(b);
mpi-genesis 1623 print_chain(a);
mpi-genesis 1624 }
mpi-genesis 1625 }
mpi-genesis 1626 else if( rc )
mpi-genesis 1627 a->error = 1;
mpi-genesis 1628
mpi-genesis 1629 if( !len ) {
mpi-genesis 1630 if( DBG_IOBUF )
mpi-genesis 1631 log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno );
mpi-genesis 1632 return -1;
mpi-genesis 1633 }
mpi-genesis 1634 a->d.len = len;
mpi-genesis 1635 a->d.start = 0;
mpi-genesis 1636 return a->d.buf[a->d.start++];
mpi-genesis 1637 }
mpi-genesis 1638 else {
mpi-genesis 1639 if( DBG_IOBUF )
mpi-genesis 1640 log_debug("iobuf-%d.%d: underflow: eof (no filter)\n",
mpi-genesis 1641 a->no, a->subno );
mpi-genesis 1642 return -1; /* no filter; return EOF */
mpi-genesis 1643 }
mpi-genesis 1644 }
mpi-genesis 1645
mpi-genesis 1646
mpi-genesis 1647 int
mpi-genesis 1648 iobuf_flush(IOBUF a)
mpi-genesis 1649 {
mpi-genesis 1650 size_t len;
mpi-genesis 1651 int rc;
mpi-genesis 1652
mpi-genesis 1653 if( a->directfp )
mpi-genesis 1654 return 0;
mpi-genesis 1655
mpi-genesis 1656 if( a->use == 3 ) { /* increase the temp buffer */
mpi-genesis 1657 char *newbuf;
mpi-genesis 1658 size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
mpi-genesis 1659
mpi-genesis 1660 if( DBG_IOBUF )
mpi-genesis 1661 log_debug("increasing temp iobuf from %lu to %lu\n",
mpi-genesis 1662 (ulong)a->d.size, (ulong)newsize );
mpi-genesis 1663 newbuf = xmalloc( newsize );
mpi-genesis 1664 memcpy( newbuf, a->d.buf, a->d.len );
mpi-genesis 1665 xfree(a->d.buf);
mpi-genesis 1666 a->d.buf = newbuf;
mpi-genesis 1667 a->d.size = newsize;
mpi-genesis 1668 return 0;
mpi-genesis 1669 }
mpi-genesis 1670 else if( a->use != 2 )
mpi-genesis 1671 log_bug("flush on non-output iobuf\n");
mpi-genesis 1672 else if( !a->filter )
mpi-genesis 1673 log_bug("iobuf_flush: no filter\n");
mpi-genesis 1674 len = a->d.len;
mpi-genesis 1675 rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
mpi-genesis 1676 if( !rc && len != a->d.len ) {
mpi-genesis 1677 log_info("iobuf_flush did not write all!\n");
mpi-genesis 1678 rc = G10ERR_WRITE_FILE;
mpi-genesis 1679 }
mpi-genesis 1680 else if( rc )
mpi-genesis 1681 a->error = 1;
mpi-genesis 1682 a->d.len = 0;
mpi-genesis 1683
mpi-genesis 1684 return rc;
mpi-genesis 1685 }
mpi-genesis 1686
mpi-genesis 1687
mpi-genesis 1688 /****************
mpi-genesis 1689 * Read a byte from the iobuf; returns -1 on EOF
mpi-genesis 1690 */
mpi-genesis 1691 int
mpi-genesis 1692 iobuf_readbyte(IOBUF a)
mpi-genesis 1693 {
mpi-genesis 1694 int c;
mpi-genesis 1695
mpi-genesis 1696 /* nlimit does not work together with unget */
mpi-genesis 1697 /* nbytes is also not valid! */
mpi-genesis 1698 if( a->unget.buf ) {
mpi-genesis 1699 if( a->unget.start < a->unget.len )
mpi-genesis 1700 return a->unget.buf[a->unget.start++];
mpi-genesis 1701 xfree(a->unget.buf);
mpi-genesis 1702 a->unget.buf = NULL;
mpi-genesis 1703 a->nofast &= ~2;
mpi-genesis 1704 }
mpi-genesis 1705
mpi-genesis 1706 if( a->nlimit && a->nbytes >= a->nlimit )
mpi-genesis 1707 return -1; /* forced EOF */
mpi-genesis 1708
mpi-genesis 1709 if( a->d.start < a->d.len ) {
mpi-genesis 1710 c = a->d.buf[a->d.start++];
mpi-genesis 1711 }
mpi-genesis 1712 else if( (c=underflow(a)) == -1 )
mpi-genesis 1713 return -1; /* EOF */
mpi-genesis 1714
mpi-genesis 1715 a->nbytes++;
mpi-genesis 1716 return c;
mpi-genesis 1717 }
mpi-genesis 1718
mpi-genesis 1719
mpi-genesis 1720 int
mpi-genesis 1721 iobuf_read(IOBUF a, byte *buf, unsigned buflen )
mpi-genesis 1722 {
mpi-genesis 1723 int c, n;
mpi-genesis 1724
mpi-genesis 1725 if( a->unget.buf || a->nlimit ) {
mpi-genesis 1726 /* handle special cases */
mpi-genesis 1727 for(n=0 ; n < buflen; n++ ) {
mpi-genesis 1728 if( (c = iobuf_readbyte(a)) == -1 ) {
mpi-genesis 1729 if( !n )
mpi-genesis 1730 return -1; /* eof */
mpi-genesis 1731 break;
mpi-genesis 1732 }
mpi-genesis 1733 else
mpi-genesis 1734 if( buf ) *buf = c;
mpi-genesis 1735 if( buf ) buf++;
mpi-genesis 1736 }
mpi-genesis 1737 return n;
mpi-genesis 1738 }
mpi-genesis 1739
mpi-genesis 1740 n = 0;
mpi-genesis 1741 do {
mpi-genesis 1742 if( n < buflen && a->d.start < a->d.len ) {
mpi-genesis 1743 unsigned size = a->d.len - a->d.start;
mpi-genesis 1744 if( size > buflen - n )
mpi-genesis 1745 size = buflen - n;
mpi-genesis 1746 if( buf )
mpi-genesis 1747 memcpy( buf, a->d.buf + a->d.start, size );
mpi-genesis 1748 n += size;
mpi-genesis 1749 a->d.start += size;
mpi-genesis 1750 if( buf )
mpi-genesis 1751 buf += size;
mpi-genesis 1752 }
mpi-genesis 1753 if( n < buflen ) {
mpi-genesis 1754 if( (c=underflow(a)) == -1 ) {
mpi-genesis 1755 a->nbytes += n;
mpi-genesis 1756 return n? n : -1/*EOF*/;
mpi-genesis 1757 }
mpi-genesis 1758 if( buf )
mpi-genesis 1759 *buf++ = c;
mpi-genesis 1760 n++;
mpi-genesis 1761 }
mpi-genesis 1762 } while( n < buflen );
mpi-genesis 1763 a->nbytes += n;
mpi-genesis 1764 return n;
mpi-genesis 1765 }
mpi-genesis 1766
mpi-genesis 1767
mpi-genesis 1768 /****************
mpi-genesis 1769 * Have a look at the iobuf.
mpi-genesis 1770 * NOTE: This only works in special cases.
mpi-genesis 1771 */
mpi-genesis 1772 int
mpi-genesis 1773 iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
mpi-genesis 1774 {
mpi-genesis 1775 int n=0;
mpi-genesis 1776
mpi-genesis 1777 if( a->filter_eof )
mpi-genesis 1778 return -1;
mpi-genesis 1779
mpi-genesis 1780 if( !(a->d.start < a->d.len) ) {
mpi-genesis 1781 if( underflow(a) == -1 )
mpi-genesis 1782 return -1;
mpi-genesis 1783 /* and unget this character */
mpi-genesis 1784 assert(a->d.start == 1);
mpi-genesis 1785 a->d.start = 0;
mpi-genesis 1786 }
mpi-genesis 1787
mpi-genesis 1788 for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
mpi-genesis 1789 *buf = a->d.buf[n];
mpi-genesis 1790 return n;
mpi-genesis 1791 }
mpi-genesis 1792
mpi-genesis 1793
mpi-genesis 1794
mpi-genesis 1795
mpi-genesis 1796 int
mpi-genesis 1797 iobuf_writebyte(IOBUF a, unsigned c)
mpi-genesis 1798 {
mpi-genesis 1799
mpi-genesis 1800 if( a->directfp )
mpi-genesis 1801 BUG();
mpi-genesis 1802
mpi-genesis 1803 if( a->d.len == a->d.size )
mpi-genesis 1804 if( iobuf_flush(a) )
mpi-genesis 1805 return -1;
mpi-genesis 1806
mpi-genesis 1807 assert( a->d.len < a->d.size );
mpi-genesis 1808 a->d.buf[a->d.len++] = c;
mpi-genesis 1809 return 0;
mpi-genesis 1810 }
mpi-genesis 1811
mpi-genesis 1812
mpi-genesis 1813 int
mpi-genesis 1814 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
mpi-genesis 1815 {
mpi-genesis 1816
mpi-genesis 1817 if( a->directfp )
mpi-genesis 1818 BUG();
mpi-genesis 1819
mpi-genesis 1820 do {
mpi-genesis 1821 if( buflen && a->d.len < a->d.size ) {
mpi-genesis 1822 unsigned size = a->d.size - a->d.len;
mpi-genesis 1823 if( size > buflen ) size = buflen;
mpi-genesis 1824 memcpy( a->d.buf + a->d.len, buf, size );
mpi-genesis 1825 buflen -= size;
mpi-genesis 1826 buf += size;
mpi-genesis 1827 a->d.len += size;
mpi-genesis 1828 }
mpi-genesis 1829 if( buflen ) {
mpi-genesis 1830 if( iobuf_flush(a) )
mpi-genesis 1831 return -1;
mpi-genesis 1832 }
mpi-genesis 1833 } while( buflen );
mpi-genesis 1834 return 0;
mpi-genesis 1835 }
mpi-genesis 1836
mpi-genesis 1837
mpi-genesis 1838 int
mpi-genesis 1839 iobuf_writestr(IOBUF a, const char *buf )
mpi-genesis 1840 {
mpi-genesis 1841 for( ; *buf; buf++ )
mpi-genesis 1842 if( iobuf_writebyte(a, *buf) )
mpi-genesis 1843 return -1;
mpi-genesis 1844 return 0;
mpi-genesis 1845 }
mpi-genesis 1846
mpi-genesis 1847
mpi-genesis 1848
mpi-genesis 1849 /****************
mpi-genesis 1850 * copy the contents of TEMP to A.
mpi-genesis 1851 */
mpi-genesis 1852 int
mpi-genesis 1853 iobuf_write_temp( IOBUF a, IOBUF temp )
mpi-genesis 1854 {
mpi-genesis 1855 while( temp->chain )
mpi-genesis 1856 pop_filter( temp, temp->filter, NULL );
mpi-genesis 1857 return iobuf_write(a, temp->d.buf, temp->d.len );
mpi-genesis 1858 }
mpi-genesis 1859
mpi-genesis 1860 /****************
mpi-genesis 1861 * copy the contents of the temp io stream to BUFFER.
mpi-genesis 1862 */
mpi-genesis 1863 size_t
mpi-genesis 1864 iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
mpi-genesis 1865 {
mpi-genesis 1866 size_t n = a->d.len;
mpi-genesis 1867
mpi-genesis 1868 if( n > buflen )
mpi-genesis 1869 n = buflen;
mpi-genesis 1870 memcpy( buffer, a->d.buf, n );
mpi-genesis 1871 return n;
mpi-genesis 1872 }
mpi-genesis 1873
mpi-genesis 1874
mpi-genesis 1875 /****************
mpi-genesis 1876 * Call this function to terminate processing of the temp stream
mpi-genesis 1877 * without closing it. This removes all filters from the stream
mpi-genesis 1878 * makes sure that iobuf_get_temp_{buffer,length}() returns correct
mpi-genesis 1879 * values.
mpi-genesis 1880 */
mpi-genesis 1881 void
mpi-genesis 1882 iobuf_flush_temp( IOBUF temp )
mpi-genesis 1883 {
mpi-genesis 1884 while( temp->chain )
mpi-genesis 1885 pop_filter( temp, temp->filter, NULL );
mpi-genesis 1886 }
mpi-genesis 1887
mpi-genesis 1888
mpi-genesis 1889 /****************
mpi-genesis 1890 * Set a limit on how many bytes may be read from the input stream A.
mpi-genesis 1891 * Setting the limit to 0 disables this feature.
mpi-genesis 1892 */
mpi-genesis 1893 void
mpi-genesis 1894 iobuf_set_limit( IOBUF a, off_t nlimit )
mpi-genesis 1895 {
mpi-genesis 1896 if( nlimit )
mpi-genesis 1897 a->nofast |= 1;
mpi-genesis 1898 else
mpi-genesis 1899 a->nofast &= ~1;
mpi-genesis 1900 a->nlimit = nlimit;
mpi-genesis 1901 a->ntotal += a->nbytes;
mpi-genesis 1902 a->nbytes = 0;
mpi-genesis 1903 }
mpi-genesis 1904
mpi-genesis 1905
mpi-genesis 1906
mpi-genesis 1907 /* Return the length of an open file A. IF OVERFLOW is not NULL it
mpi-genesis 1908 will be set to true if the file is larger than what off_t can cope
mpi-genesis 1909 with. The function return 0 on error or on overflow condition. */
mpi-genesis 1910 off_t
mpi-genesis 1911 iobuf_get_filelength (IOBUF a, int *overflow )
mpi-genesis 1912 {
mpi-genesis 1913 struct stat st;
mpi-genesis 1914
mpi-genesis 1915 if (overflow)
mpi-genesis 1916 *overflow = 0;
mpi-genesis 1917
mpi-genesis 1918 if( a->directfp ) {
mpi-genesis 1919 FILE *fp = a->directfp;
mpi-genesis 1920
mpi-genesis 1921 if( !fstat(fileno(fp), &st) )
mpi-genesis 1922 return st.st_size;
mpi-genesis 1923 log_error("fstat() failed: %s\n", strerror(errno) );
mpi-genesis 1924 return 0;
mpi-genesis 1925 }
mpi-genesis 1926
mpi-genesis 1927 /* Hmmm: file_filter may have already been removed */
mpi-genesis 1928 for( ; a; a = a->chain )
mpi-genesis 1929 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 1930 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 1931 FILEP_OR_FD fp = b->fp;
mpi-genesis 1932
mpi-genesis 1933 #if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO)
mpi-genesis 1934 ulong size;
mpi-genesis 1935 static int (* __stdcall get_file_size_ex)
mpi-genesis 1936 (void *handle, LARGE_INTEGER *size);
mpi-genesis 1937 static int get_file_size_ex_initialized;
mpi-genesis 1938
mpi-genesis 1939 if (!get_file_size_ex_initialized)
mpi-genesis 1940 {
mpi-genesis 1941 void *handle;
mpi-genesis 1942
mpi-genesis 1943 handle = dlopen ("kernel32.dll", RTLD_LAZY);
mpi-genesis 1944 if (handle)
mpi-genesis 1945 {
mpi-genesis 1946 get_file_size_ex = dlsym (handle, "GetFileSizeEx");
mpi-genesis 1947 if (!get_file_size_ex)
mpi-genesis 1948 dlclose (handle);
mpi-genesis 1949 }
mpi-genesis 1950 get_file_size_ex_initialized = 1;
mpi-genesis 1951 }
mpi-genesis 1952
mpi-genesis 1953 if (get_file_size_ex)
mpi-genesis 1954 {
mpi-genesis 1955 /* This is a newer system with GetFileSizeEx; we use
mpi-genesis 1956 this then becuase it seem that GetFileSize won't
mpi-genesis 1957 return a proper error in case a file is larger than
mpi-genesis 1958 4GB. */
mpi-genesis 1959 LARGE_INTEGER size;
mpi-genesis 1960
mpi-genesis 1961 if (get_file_size_ex (fp, &size))
mpi-genesis 1962 {
mpi-genesis 1963 if (!size.u.HighPart)
mpi-genesis 1964 return size.u.LowPart;
mpi-genesis 1965 if (overflow)
mpi-genesis 1966 *overflow = 1;
mpi-genesis 1967 return 0;
mpi-genesis 1968 }
mpi-genesis 1969 }
mpi-genesis 1970 else
mpi-genesis 1971 {
mpi-genesis 1972 if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
mpi-genesis 1973 return size;
mpi-genesis 1974 }
mpi-genesis 1975 log_error ("GetFileSize for handle %p failed: %s\n",
mpi-genesis 1976 fp, w32_strerror (0));
mpi-genesis 1977 #else
mpi-genesis 1978 if( !fstat(my_fileno(fp), &st) )
mpi-genesis 1979 return st.st_size;
mpi-genesis 1980 log_error("fstat() failed: %s\n", strerror(errno) );
mpi-genesis 1981 #endif
mpi-genesis 1982 break;
mpi-genesis 1983 }
mpi-genesis 1984
mpi-genesis 1985 return 0;
mpi-genesis 1986 }
mpi-genesis 1987
mpi-genesis 1988
mpi-genesis 1989 /* Return the file descriptor of the underlying file or -1 if it is
mpi-genesis 1990 not available. */
mpi-genesis 1991 int
mpi-genesis 1992 iobuf_get_fd (IOBUF a)
mpi-genesis 1993 {
mpi-genesis 1994 if (a->directfp)
mpi-genesis 1995 return fileno ( (FILE*)a->directfp );
mpi-genesis 1996
mpi-genesis 1997 for ( ; a; a = a->chain )
mpi-genesis 1998 if (!a->chain && a->filter == file_filter)
mpi-genesis 1999 {
mpi-genesis 2000 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 2001 FILEP_OR_FD fp = b->fp;
mpi-genesis 2002
mpi-genesis 2003 return my_fileno (fp);
mpi-genesis 2004 }
mpi-genesis 2005
mpi-genesis 2006 return -1;
mpi-genesis 2007 }
mpi-genesis 2008
mpi-genesis 2009
mpi-genesis 2010 /****************
mpi-genesis 2011 * Tell the file position, where the next read will take place
mpi-genesis 2012 */
mpi-genesis 2013 off_t
mpi-genesis 2014 iobuf_tell( IOBUF a )
mpi-genesis 2015 {
mpi-genesis 2016 return a->ntotal + a->nbytes;
mpi-genesis 2017 }
mpi-genesis 2018
mpi-genesis 2019
mpi-genesis 2020 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
mpi-genesis 2021
mpi-genesis 2022 #ifdef HAVE_LIMITS_H
mpi-genesis 2023 # include <limits.h>
mpi-genesis 2024 #endif
mpi-genesis 2025 #ifndef LONG_MAX
mpi-genesis 2026 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
mpi-genesis 2027 #endif
mpi-genesis 2028 #ifndef LONG_MIN
mpi-genesis 2029 # define LONG_MIN (-1 - LONG_MAX)
mpi-genesis 2030 #endif
mpi-genesis 2031
mpi-genesis 2032 /****************
mpi-genesis 2033 * A substitute for fseeko, for hosts that don't have it.
mpi-genesis 2034 */
mpi-genesis 2035 static int
mpi-genesis 2036 fseeko( FILE *stream, off_t newpos, int whence )
mpi-genesis 2037 {
mpi-genesis 2038 while( newpos != (long) newpos ) {
mpi-genesis 2039 long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
mpi-genesis 2040 if( fseek( stream, pos, whence ) != 0 )
mpi-genesis 2041 return -1;
mpi-genesis 2042 newpos -= pos;
mpi-genesis 2043 whence = SEEK_CUR;
mpi-genesis 2044 }
mpi-genesis 2045 return fseek( stream, (long)newpos, whence );
mpi-genesis 2046 }
mpi-genesis 2047 #endif
mpi-genesis 2048
mpi-genesis 2049 /****************
mpi-genesis 2050 * This is a very limited implementation. It simply discards all internal
mpi-genesis 2051 * buffering and removes all filters but the first one.
mpi-genesis 2052 */
mpi-genesis 2053 int
mpi-genesis 2054 iobuf_seek( IOBUF a, off_t newpos )
mpi-genesis 2055 {
mpi-genesis 2056 file_filter_ctx_t *b = NULL;
mpi-genesis 2057
mpi-genesis 2058 if( a->directfp ) {
mpi-genesis 2059 FILE *fp = a->directfp;
mpi-genesis 2060 if( fseeko( fp, newpos, SEEK_SET ) ) {
mpi-genesis 2061 log_error("can't seek: %s\n", strerror(errno) );
mpi-genesis 2062 return -1;
mpi-genesis 2063 }
mpi-genesis 2064 clearerr(fp);
mpi-genesis 2065 }
mpi-genesis 2066 else {
mpi-genesis 2067 for( ; a; a = a->chain ) {
mpi-genesis 2068 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 2069 b = a->filter_ov;
mpi-genesis 2070 break;
mpi-genesis 2071 }
mpi-genesis 2072 }
mpi-genesis 2073 if( !a )
mpi-genesis 2074 return -1;
mpi-genesis 2075 #ifdef FILE_FILTER_USES_STDIO
mpi-genesis 2076 if( fseeko( b->fp, newpos, SEEK_SET ) ) {
mpi-genesis 2077 log_error("can't fseek: %s\n", strerror(errno) );
mpi-genesis 2078 return -1;
mpi-genesis 2079 }
mpi-genesis 2080 #else
mpi-genesis 2081 #ifdef HAVE_DOSISH_SYSTEM
mpi-genesis 2082 if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff ) {
mpi-genesis 2083 log_error ("SetFilePointer failed on handle %p: %s\n",
mpi-genesis 2084 b->fp, w32_strerror (0));
mpi-genesis 2085 return -1;
mpi-genesis 2086 }
mpi-genesis 2087 #else
mpi-genesis 2088 if ( lseek (b->fp, newpos, SEEK_SET) == (off_t)-1 ) {
mpi-genesis 2089 log_error("can't lseek: %s\n", strerror(errno) );
mpi-genesis 2090 return -1;
mpi-genesis 2091 }
mpi-genesis 2092 #endif
mpi-genesis 2093 #endif
mpi-genesis 2094 }
mpi-genesis 2095 a->d.len = 0; /* discard buffer */
mpi-genesis 2096 a->d.start = 0;
mpi-genesis 2097 a->nbytes = 0;
mpi-genesis 2098 a->nlimit = 0;
mpi-genesis 2099 a->nofast &= ~1;
mpi-genesis 2100 a->ntotal = newpos;
mpi-genesis 2101 a->error = 0;
mpi-genesis 2102 /* remove filters, but the last */
mpi-genesis 2103 if( a->chain )
mpi-genesis 2104 log_debug("pop_filter called in iobuf_seek - please report\n");
mpi-genesis 2105 while( a->chain )
mpi-genesis 2106 pop_filter( a, a->filter, NULL );
mpi-genesis 2107
mpi-genesis 2108 return 0;
mpi-genesis 2109 }
mpi-genesis 2110
mpi-genesis 2111
mpi-genesis 2112
mpi-genesis 2113
mpi-genesis 2114
mpi-genesis 2115
mpi-genesis 2116 /****************
mpi-genesis 2117 * Retrieve the real filename
mpi-genesis 2118 */
mpi-genesis 2119 const char *
mpi-genesis 2120 iobuf_get_real_fname( IOBUF a )
mpi-genesis 2121 {
mpi-genesis 2122 if( a->real_fname )
mpi-genesis 2123 return a->real_fname;
mpi-genesis 2124
mpi-genesis 2125 /* the old solution */
mpi-genesis 2126 for( ; a; a = a->chain )
mpi-genesis 2127 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 2128 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 2129 return b->print_only_name? NULL : b->fname;
mpi-genesis 2130 }
mpi-genesis 2131
mpi-genesis 2132 return NULL;
mpi-genesis 2133 }
mpi-genesis 2134
mpi-genesis 2135
mpi-genesis 2136 /****************
mpi-genesis 2137 * Retrieve the filename
mpi-genesis 2138 */
mpi-genesis 2139 const char *
mpi-genesis 2140 iobuf_get_fname( IOBUF a )
mpi-genesis 2141 {
mpi-genesis 2142 for( ; a; a = a->chain )
mpi-genesis 2143 if( !a->chain && a->filter == file_filter ) {
mpi-genesis 2144 file_filter_ctx_t *b = a->filter_ov;
mpi-genesis 2145 return b->fname;
mpi-genesis 2146 }
mpi-genesis 2147
mpi-genesis 2148 return NULL;
mpi-genesis 2149 }
mpi-genesis 2150
mpi-genesis 2151
mpi-genesis 2152 /****************
mpi-genesis 2153 * enable partial block mode as described in the OpenPGP draft.
mpi-genesis 2154 * LEN is the first length byte on read, but ignored on writes.
mpi-genesis 2155 */
mpi-genesis 2156 void
mpi-genesis 2157 iobuf_set_partial_block_mode( IOBUF a, size_t len )
mpi-genesis 2158 {
mpi-genesis 2159 block_filter_ctx_t *ctx = xmalloc_clear( sizeof *ctx );
mpi-genesis 2160
mpi-genesis 2161 assert( a->use == 1 || a->use == 2 );
mpi-genesis 2162 ctx->use = a->use;
mpi-genesis 2163 if( !len ) {
mpi-genesis 2164 if( a->use == 1 )
mpi-genesis 2165 log_debug("pop_filter called in set_partial_block_mode"
mpi-genesis 2166 " - please report\n");
mpi-genesis 2167 pop_filter(a, block_filter, NULL );
mpi-genesis 2168 }
mpi-genesis 2169 else {
mpi-genesis 2170 ctx->partial = 1;
mpi-genesis 2171 ctx->size = 0;
mpi-genesis 2172 ctx->first_c = len;
mpi-genesis 2173 iobuf_push_filter(a, block_filter, ctx );
mpi-genesis 2174 }
mpi-genesis 2175 }
mpi-genesis 2176
mpi-genesis 2177
mpi-genesis 2178 /****************
mpi-genesis 2179 * Same as fgets() but if the buffer is too short a larger one will
mpi-genesis 2180 * be allocated up to some limit *max_length.
mpi-genesis 2181 * A line is considered a byte stream ending in a LF.
mpi-genesis 2182 * Returns the length of the line. EOF is indicated by a line of
mpi-genesis 2183 * length zero. The last LF may be missing due to an EOF.
mpi-genesis 2184 * is max_length is zero on return, the line has been truncated.
mpi-genesis 2185 *
mpi-genesis 2186 * Note: The buffer is allocated with enough space to append a CR,LF,EOL
mpi-genesis 2187 */
mpi-genesis 2188 unsigned
mpi-genesis 2189 iobuf_read_line( IOBUF a, byte **addr_of_buffer,
mpi-genesis 2190 unsigned *length_of_buffer, unsigned *max_length )
mpi-genesis 2191 {
mpi-genesis 2192 int c;
mpi-genesis 2193 char *buffer = *addr_of_buffer;
mpi-genesis 2194 unsigned length = *length_of_buffer;
mpi-genesis 2195 unsigned nbytes = 0;
mpi-genesis 2196 unsigned maxlen = *max_length;
mpi-genesis 2197 char *p;
mpi-genesis 2198
mpi-genesis 2199 if( !buffer ) { /* must allocate a new buffer */
mpi-genesis 2200 length = 256;
mpi-genesis 2201 buffer = xmalloc( length );
mpi-genesis 2202 *addr_of_buffer = buffer;
mpi-genesis 2203 *length_of_buffer = length;
mpi-genesis 2204 }
mpi-genesis 2205
mpi-genesis 2206 length -= 3; /* reserve 3 bytes (cr,lf,eol) */
mpi-genesis 2207 p = buffer;
mpi-genesis 2208 while( (c=iobuf_get(a)) != -1 ) {
mpi-genesis 2209 if( nbytes == length ) { /* increase the buffer */
mpi-genesis 2210 if( length > maxlen ) { /* this is out limit */
mpi-genesis 2211 /* skip the rest of the line */
mpi-genesis 2212 while( c != '\n' && (c=iobuf_get(a)) != -1 )
mpi-genesis 2213 ;
mpi-genesis 2214 *p++ = '\n'; /* always append a LF (we have reserved space) */
mpi-genesis 2215 nbytes++;
mpi-genesis 2216 *max_length = 0; /* indicate truncation */
mpi-genesis 2217 break;
mpi-genesis 2218 }
mpi-genesis 2219 length += 3; /* correct for the reserved byte */
mpi-genesis 2220 length += length < 1024? 256 : 1024;
mpi-genesis 2221 buffer = xrealloc( buffer, length );
mpi-genesis 2222 *addr_of_buffer = buffer;
mpi-genesis 2223 *length_of_buffer = length;
mpi-genesis 2224 length -= 3; /* and reserve again */
mpi-genesis 2225 p = buffer + nbytes;
mpi-genesis 2226 }
mpi-genesis 2227 *p++ = c;
mpi-genesis 2228 nbytes++;
mpi-genesis 2229 if( c == '\n' )
mpi-genesis 2230 break;
mpi-genesis 2231 }
mpi-genesis 2232 *p = 0; /* make sure the line is a string */
mpi-genesis 2233
mpi-genesis 2234 return nbytes;
mpi-genesis 2235 }
mpi-genesis 2236
mpi-genesis 2237 /* This is the non iobuf specific function */
mpi-genesis 2238 int
mpi-genesis 2239 iobuf_translate_file_handle ( int fd, int for_write )
mpi-genesis 2240 {
mpi-genesis 2241 #ifdef _WIN32
mpi-genesis 2242 {
mpi-genesis 2243 int x;
mpi-genesis 2244
mpi-genesis 2245 if ( fd <= 2 )
mpi-genesis 2246 return fd; /* do not do this for error, stdin, stdout, stderr */
mpi-genesis 2247
mpi-genesis 2248 x = _open_osfhandle ( fd, for_write? 1:0 );
mpi-genesis 2249 if (x==-1 )
mpi-genesis 2250 log_error ("failed to translate osfhandle %p\n", (void*)fd );
mpi-genesis 2251 else {
mpi-genesis 2252 /*log_info ("_open_osfhandle %p yields %d%s\n",
mpi-genesis 2253 (void*)fd, x, for_write? " for writing":"" );*/
mpi-genesis 2254 fd = x;
mpi-genesis 2255 }
mpi-genesis 2256 }
mpi-genesis 2257 #endif
mpi-genesis 2258 return fd;
mpi-genesis 2259 }
mpi-genesis 2260
mpi-genesis 2261 static int
mpi-genesis 2262 translate_file_handle ( int fd, int for_write )
mpi-genesis 2263 {
mpi-genesis 2264 #ifdef _WIN32
mpi-genesis 2265 #ifdef FILE_FILTER_USES_STDIO
mpi-genesis 2266 fd = iobuf_translate_file_handle (fd, for_write);
mpi-genesis 2267 #else
mpi-genesis 2268 {
mpi-genesis 2269 int x;
mpi-genesis 2270
mpi-genesis 2271 if ( fd == 0 )
mpi-genesis 2272 x = (int)GetStdHandle (STD_INPUT_HANDLE);
mpi-genesis 2273 else if (fd == 1)
mpi-genesis 2274 x = (int)GetStdHandle (STD_OUTPUT_HANDLE);
mpi-genesis 2275 else if (fd == 2)
mpi-genesis 2276 x = (int)GetStdHandle (STD_ERROR_HANDLE);
mpi-genesis 2277 else
mpi-genesis 2278 x = fd;
mpi-genesis 2279
mpi-genesis 2280 if (x == -1)
mpi-genesis 2281 log_debug ("GetStdHandle(%d) failed: %s\n",
mpi-genesis 2282 fd, w32_strerror (0));
mpi-genesis 2283
mpi-genesis 2284 fd = x;
mpi-genesis 2285 }
mpi-genesis 2286 #endif
mpi-genesis 2287 #endif
mpi-genesis 2288 return fd;
mpi-genesis 2289 }
mpi-genesis 2290
mpi-genesis 2291
mpi-genesis 2292 void
mpi-genesis 2293 iobuf_skip_rest(IOBUF a, unsigned long n, int partial)
mpi-genesis 2294 {
mpi-genesis 2295 if ( partial ) {
mpi-genesis 2296 for (;;) {
mpi-genesis 2297 if (a->nofast || a->d.start >= a->d.len) {
mpi-genesis 2298 if (iobuf_readbyte (a) == -1) {
mpi-genesis 2299 break;
mpi-genesis 2300 }
mpi-genesis 2301 } else {
mpi-genesis 2302 unsigned long count = a->d.len - a->d.start;
mpi-genesis 2303 a->nbytes += count;
mpi-genesis 2304 a->d.start = a->d.len;
mpi-genesis 2305 }
mpi-genesis 2306 }
mpi-genesis 2307 } else {
mpi-genesis 2308 unsigned long remaining = n;
mpi-genesis 2309 while (remaining > 0) {
mpi-genesis 2310 if (a->nofast || a->d.start >= a->d.len) {
mpi-genesis 2311 if (iobuf_readbyte (a) == -1) {
mpi-genesis 2312 break;
mpi-genesis 2313 }
mpi-genesis 2314 --remaining;
mpi-genesis 2315 } else {
mpi-genesis 2316 unsigned long count = a->d.len - a->d.start;
mpi-genesis 2317 if (count > remaining) {
mpi-genesis 2318 count = remaining;
mpi-genesis 2319 }
mpi-genesis 2320 a->nbytes += count;
mpi-genesis 2321 a->d.start += count;
mpi-genesis 2322 remaining -= count;
mpi-genesis 2323 }
mpi-genesis 2324 }
mpi-genesis 2325 }
mpi-genesis 2326 }