aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/iobuf.c192
-rw-r--r--common/iobuf.h487
2 files changed, 530 insertions, 149 deletions
diff --git a/common/iobuf.c b/common/iobuf.c
index 7d75e33f7..e859a5c70 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -133,9 +133,9 @@ typedef struct
} sock_filter_ctx_t;
#endif /*HAVE_W32_SYSTEM*/
-/* The first partial length header block must be of size 512
- * to make it easier (and efficienter) we use a min. block size of 512
- * for all chunks (but the last one) */
+/* The first partial length header block must be of size 512 to make
+ * it easier (and more efficient) we use a min. block size of 512 for
+ * all chunks (but the last one) */
#define OP_MIN_PARTIAL_CHUNK 512
#define OP_MIN_PARTIAL_CHUNK_2POW 9
@@ -156,8 +156,8 @@ block_filter_ctx_t;
/* Global flag to tell whether special file names are enabled. See
- gpg.c for an explanation of these file names. FIXME: it does not
- belong into the iobuf subsystem. */
+ gpg.c for an explanation of these file names. FIXME: This does not
+ belong in the iobuf subsystem. */
static int special_names_enabled;
/* Local prototypes. */
@@ -401,7 +401,7 @@ fd_cache_close (const char *fname, gnupg_fd_t fp)
}
/*
- * Do an direct_open on FNAME but first try to reuse one from the fd_cache
+ * Do a direct_open on FNAME but first try to reuse one from the fd_cache
*/
static gnupg_fd_t
fd_cache_open (const char *fname, const char *mode)
@@ -440,30 +440,6 @@ fd_cache_open (const char *fname, const char *mode)
}
-/****************
- * Read data from a file into buf which has an allocated length of *LEN.
- * return the number of read bytes in *LEN. OPAQUE is the FILE * of
- * the stream. A is not used.
- * control may be:
- * IOBUFCTRL_INIT: called just before the function is linked into the
- * list of function. This can be used to prepare internal
- * data structures of the function.
- * IOBUFCTRL_FREE: called just before the function is removed from the
- * list of functions and can be used to release internal
- * data structures or close a file etc.
- * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
- * with new stuff. *RET_LEN is the available size of the
- * buffer, and should be set to the number of bytes
- * which were put into the buffer. The function
- * returns 0 to indicate success, -1 on EOF and
- * GPG_ERR_xxxxx for other errors.
- *
- * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
- * *RET_LAN is the number of bytes in BUF.
- *
- * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel. The
- * filter may take appropriate action on this message.
- */
static int
file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
size_t * ret_len)
@@ -1117,13 +1093,6 @@ iobuf_print_chain (iobuf_t a)
return 0;
}
-/* Allocate a new io buffer, with no function assigned.
-
- USE is the desired usage: IOBUF_INPUT for input, IOBUF_OUTPUT for
- output, or IOBUF_TEMP for a temp buffer.
-
- BUFSIZE is a suggested buffer size.
- */
iobuf_t
iobuf_alloc (int use, size_t bufsize)
{
@@ -1233,19 +1202,10 @@ iobuf_cancel (iobuf_t a)
}
-/****************
- * create a temporary iobuf, which can be used to collect stuff
- * in an iobuf and later be written by iobuf_write_temp() to another
- * iobuf.
- */
iobuf_t
-iobuf_temp ()
+iobuf_temp (void)
{
- iobuf_t a;
-
- a = iobuf_alloc (IOBUF_TEMP, IOBUF_BUFFER_SIZE);
-
- return a;
+ return iobuf_alloc (IOBUF_TEMP, IOBUF_BUFFER_SIZE);
}
iobuf_t
@@ -1290,8 +1250,6 @@ check_special_filename (const char *fname)
}
-/* This fucntion returns true if FNAME indicates a PIPE (stdout or
- stderr) or a special file name if those are enabled. */
int
iobuf_is_pipe_filename (const char *fname)
{
@@ -1359,10 +1317,6 @@ do_open (const char *fname, int special_filenames,
return a;
}
-/****************
- * Create a head iobuf for reading from a file
- * returns: NULL if an error occures and sets errno
- */
iobuf_t
iobuf_open (const char *fname)
{
@@ -1410,8 +1364,6 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
}
-/* Create a head iobuf for reading or writing from/to a file Returns:
- * NULL and sets ERRNO if an error occured. */
iobuf_t
iobuf_fdopen (int fd, const char *mode)
{
@@ -1587,11 +1539,51 @@ iobuf_push_filter2 (iobuf_t a,
return GPG_ERR_BAD_DATA;
}
- /* make a copy of the current stream, so that
- * A is the new stream and B the original one.
- * The contents of the buffers are transferred to the
- * new stream.
- */
+ /* We want to create a new filter and put it in front of A. A
+ simple implementation would do:
+
+ b = iobuf_alloc (...);
+ b->chain = a;
+ return a;
+
+ This is a bit problematic: A is the head of the pipeline and
+ there are potentially many pointers to it. Requiring the caller
+ to update all of these pointers is a burden.
+
+ An alternative implementation would add a level of indirection.
+ For instance, we could use a pipeline object, which contains a
+ pointer to the first filter in the pipeline. This is not what we
+ do either.
+
+ Instead, we allocate a new buffer (B) and copy the first filter's
+ state into that and use the initial buffer (A) for the new
+ filter. One limitation of this approach is that it is not
+ practical to maintain a pointer to a specific filter's state.
+
+ Before:
+
+ A
+ |
+ v 0x100 0x200
+ +----------+ +----------+
+ | filter x |--------->| filter y |---->....
+ +----------+ +----------+
+
+ After: B
+ |
+ v 0x300
+ +----------+
+ A | filter x |
+ | +----------+
+ v 0x100 ^ v 0x200
+ +----------+ +----------+
+ | filter w | | filter y |---->....
+ +----------+ +----------+
+
+ Note: filter x's address changed from 0x100 to 0x300, but A still
+ points to the head of the pipeline.
+ */
+
b = xmalloc (sizeof *b);
memcpy (b, a, sizeof *b);
/* fixme: it is stupid to keep a copy of the name at every level
@@ -1938,9 +1930,6 @@ filter_flush (iobuf_t a)
}
-/****************
- * Read a byte from the iobuf; returns -1 on EOF
- */
int
iobuf_readbyte (iobuf_t a)
{
@@ -1956,6 +1945,9 @@ iobuf_readbyte (iobuf_t a)
else if ((c = underflow (a, 1)) == -1)
return -1; /* EOF */
+ /* Note: if underflow doesn't return EOF, then it returns the first
+ byte that was read and advances a->d.start appropriately. */
+
a->nbytes++;
return c;
}
@@ -1990,6 +1982,7 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
do
{
if (n < buflen && a->d.start < a->d.len)
+ /* Drain the buffer. */
{
unsigned size = a->d.len - a->d.start;
if (size > buflen - n)
@@ -2002,8 +1995,13 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
buf += size;
}
if (n < buflen)
+ /* Draining the internal buffer didn't fill BUFFER. Call
+ underflow to read more data into the filter's internal
+ buffer. */
{
if ((c = underflow (a, 1)) == -1)
+ /* EOF. If we managed to read something, don't return EOF
+ now. */
{
a->nbytes += n;
return n ? n : -1 /*EOF*/;
@@ -2120,9 +2118,6 @@ iobuf_writestr (iobuf_t a, const char *buf)
-/****************
- * copy the contents of TEMP to A.
- */
int
iobuf_write_temp (iobuf_t a, iobuf_t temp)
{
@@ -2131,9 +2126,6 @@ iobuf_write_temp (iobuf_t a, iobuf_t temp)
return iobuf_write (a, temp->d.buf, temp->d.len);
}
-/****************
- * copy the contents of the temp io stream to BUFFER.
- */
size_t
iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
{
@@ -2158,12 +2150,6 @@ iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
}
-/****************
- * Call this function to terminate processing of the temp stream
- * without closing it. This removes all filters from the stream
- * makes sure that iobuf_get_temp_{buffer,length}() returns correct
- * values.
- */
void
iobuf_flush_temp (iobuf_t temp)
{
@@ -2172,10 +2158,6 @@ iobuf_flush_temp (iobuf_t temp)
}
-/****************
- * Set a limit on how many bytes may be read from the input stream A.
- * Setting the limit to 0 disables this feature.
- */
void
iobuf_set_limit (iobuf_t a, off_t nlimit)
{
@@ -2190,9 +2172,6 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
-/* Return the length of an open file A. IF OVERFLOW is not NULL it
- will be set to true if the file is larger than what off_t can cope
- with. The function return 0 on error or on overflow condition. */
off_t
iobuf_get_filelength (iobuf_t a, int *overflow)
{
@@ -2263,8 +2242,6 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
}
-/* Return the file descriptor of the underlying file or -1 if it is
- not available. */
int
iobuf_get_fd (iobuf_t a)
{
@@ -2281,10 +2258,6 @@ iobuf_get_fd (iobuf_t a)
}
-
-/****************
- * Tell the file position, where the next read will take place
- */
off_t
iobuf_tell (iobuf_t a)
{
@@ -2322,10 +2295,6 @@ fseeko (FILE * stream, off_t newpos, int whence)
}
#endif
-/****************
- * This is a very limited implementation. It simply discards all internal
- * buffering and removes all filters but the first one.
- */
int
iobuf_seek (iobuf_t a, off_t newpos)
{
@@ -2367,6 +2336,16 @@ iobuf_seek (iobuf_t a, off_t newpos)
a->nofast = 0;
a->ntotal = newpos;
a->error = 0;
+
+ /* It is impossible for A->CHAIN to be non-NULL. If A is an INPUT
+ or OUTPUT buffer, then we find the last filter, which is defined
+ as A->CHAIN being NULL. If A is a TEMP filter, then A must be
+ the only filter in the pipe: when iobuf_push_filter adds a filter
+ to the front of a pipeline, it sets the new filter to be an
+ OUTPUT filter if the pipeline is an OUTPUT or TEMP pipeline and
+ to be an INPUT filter if the pipeline is an INPUT pipeline.
+ Thus, only the last filter in a TEMP pipeline can be a */
+
/* remove filters, but the last */
if (a->chain)
log_debug ("pop_filter called in iobuf_seek - please report\n");
@@ -2381,11 +2360,6 @@ iobuf_seek (iobuf_t a, off_t newpos)
-/****************
- * Retrieve the real filename. This is the filename actually used on
- * disk and not a made up one. Returns NULL if no real filename is
- * available.
- */
const char *
iobuf_get_real_fname (iobuf_t a)
{
@@ -2404,9 +2378,6 @@ iobuf_get_real_fname (iobuf_t a)
}
-/****************
- * Retrieve the filename. This name should only be used in diagnostics.
- */
const char *
iobuf_get_fname (iobuf_t a)
{
@@ -2419,7 +2390,6 @@ iobuf_get_fname (iobuf_t a)
return NULL;
}
-/* Same as iobuf_get_fname but never returns NULL. */
const char *
iobuf_get_fname_nonnull (iobuf_t a)
{
@@ -2446,6 +2416,14 @@ iobuf_set_partial_block_mode (iobuf_t a, size_t len)
if (a->use == IOBUF_INPUT)
log_debug ("pop_filter called in set_partial_block_mode"
" - please report\n");
+ /* XXX: This pop_filter doesn't make sense. Since we haven't
+ actually added the filter to the pipeline yet, why are we
+ popping anything? Moreover, since we don't report an error,
+ the caller won't directly see an error. I think that it
+ would be better to push the filter and set a->error to
+ GPG_ERR_BAD_DATA, but Werner thinks it's impossible for len
+ to be 0 (but he doesn't want to remove the check just in
+ case). */
pop_filter (a, block_filter, NULL);
}
else
@@ -2459,16 +2437,6 @@ iobuf_set_partial_block_mode (iobuf_t a, size_t len)
-/****************
- * Same as fgets() but if the buffer is too short a larger one will
- * be allocated up to some limit *max_length.
- * A line is considered a byte stream ending in a LF.
- * Returns the length of the line. EOF is indicated by a line of
- * length zero. The last LF may be missing due to an EOF.
- * is max_length is zero on return, the line has been truncated.
- *
- * Note: The buffer is allocated with enough space to append a CR,LF,EOL
- */
unsigned int
iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
unsigned *length_of_buffer, unsigned *max_length)
diff --git a/common/iobuf.h b/common/iobuf.h
index 5cfccb8f0..7157e0f44 100644
--- a/common/iobuf.h
+++ b/common/iobuf.h
@@ -31,6 +31,63 @@
#ifndef GNUPG_COMMON_IOBUF_H
#define GNUPG_COMMON_IOBUF_H
+/* An iobuf is basically a filter in a pipeline.
+
+ Consider the following command, which consists of three filters
+ that are chained together:
+
+ $ cat file | base64 --decode | gunzip
+
+ The first filter reads the file from the file system and sends that
+ data to the second filter. The second filter decodes
+ base64-encoded data and sends the data to the third and last
+ filter. The last filter decompresses the data and the result is
+ displayed on the terminal. The iobuf system works in the same way
+ where each iobuf is a filter and the individual iobufs can be
+ chained together.
+
+ There are number of predefined filters. iobuf_open(), for
+ instance, creates a filter that reads from a specified file. And,
+ iobuf_temp_with_content() creates a filter that returns some
+ specified contents. There are also filters for writing content.
+ iobuf_openrw opens a file for writing. iobuf_temp creates a filter
+ that writes data to a fixed-sized buffer.
+
+ To chain filters together, you use the iobuf_push_filter()
+ function. The filters are chained together using the chain field
+ in the iobuf_t.
+
+ A pipeline can only be used for reading (IOBUF_INPUT) or for
+ writing (IOBUF_OUTPUT / IOBUF_TEMP). When reading, data flows from
+ the last filter towards the first. That is, the user calls
+ iobuf_read(), the module reads from the first filter, which gets
+ its input from the second filter, etc. When writing, data flows
+ from the first filter towards the last. In this case, when the
+ user calls iobuf_write(), the data is written to the first filter,
+ which writes the transformed data to the second filter, etc.
+
+ An iobuf_t contains some state about the filter. For instance, it
+ indicates if the filter has already returned EOF (filter_eof) and
+ the next filter in the pipeline, if any (chain). It also contains
+ a function pointer, filter. This is a generic function. It is
+ called when input is needed or output is available. In this case
+ it is passed a pointer to some filter-specific persistent state
+ (filter_ov), the actual operation, the next filter in the chain, if
+ any, and a buffer that either contains the contents to write, if
+ the pipeline is setup to write data, or is the place to store data,
+ if the pipeline is setup to read data.
+
+
+ Unlike a Unix pipeline, an IOBUF pipeline can return EOF multiple
+ times. This is similar to the following:
+
+ { cat file1; cat file2; } | grep foo
+
+ However, instead of grep seeing a single stream, grep would see
+ each byte stream followed by an EOF marker. (When a filter returns
+ EOF, the EOF is returned to the user exactly once and then the
+ filter is removed from the pipeline.) */
+
/* For estream_t. */
#include <gpg-error.h>
@@ -40,13 +97,16 @@
#define DBG_IOBUF iobuf_debug_mode
/* Filter control modes. */
-#define IOBUFCTRL_INIT 1
-#define IOBUFCTRL_FREE 2
-#define IOBUFCTRL_UNDERFLOW 3
-#define IOBUFCTRL_FLUSH 4
-#define IOBUFCTRL_DESC 5
-#define IOBUFCTRL_CANCEL 6
-#define IOBUFCTRL_USER 16
+enum
+ {
+ IOBUFCTRL_INIT = 1,
+ IOBUFCTRL_FREE = 2,
+ IOBUFCTRL_UNDERFLOW = 3,
+ IOBUFCTRL_FLUSH = 4,
+ IOBUFCTRL_DESC = 5,
+ IOBUFCTRL_CANCEL = 6,
+ IOBUFCTRL_USER = 16
+ };
/* Command codes for iobuf_ioctl. */
@@ -60,8 +120,17 @@ typedef enum
enum
{
+ /* Pipeline is in input mode. The data flows from the end to the
+ beginning. That is, when reading from the pipeline, the first
+ filter gets its input from the second filter, etc. */
IOBUF_INPUT=1,
+ /* Pipeline is in output mode. The data flows from the beginning
+ to the end. That is, when writing to the pipeline, the user
+ writes to the first filter, which transforms the data and sends
+ it to the second filter, etc. */
IOBUF_OUTPUT=2,
+ /* Pipeline is in output mode. The last filter in the pipeline is
+ a temporary buffer that grows as necessary. */
IOBUF_TEMP=3
};
@@ -75,33 +144,105 @@ struct iobuf_struct
/* The type of filter. Either IOBUF_INPUT, IOBUF_OUTPUT or
IOBUF_TEMP. */
int use;
+
+ /* nlimit can be changed using iobuf_set_limit. If non-zero, it is
+ the number of additional bytes that can be read from the filter
+ before EOF is forcefully returned. */
off_t nlimit;
- off_t nbytes; /* Used together with nlimit. */
- off_t ntotal; /* Total bytes read (position of stream). */
+ /* nbytes if the number of bytes that have been read (using
+ iobuf_get / iobuf_readbyte / iobuf_read) since the last call to
+ iobuf_set_limit. */
+ off_t nbytes;
+
+ /* The number of bytes read prior to the last call to
+ iobuf_set_limit. Thus, the total bytes read (i.e., the position
+ of stream) is ntotal + nbytes. */
+ off_t ntotal;
/* Whether we need to read from the filter one byte at a time or
whether we can do bulk reads. We need to read one byte at a time
if a limit (set via iobuf_set_limit) is active. */
int nofast;
+
+ /* A buffer for unread/unwritten data.
+
+ For an output pipeline (IOBUF_OUTPUT), this is the data that has
+ not yet been written to the filter. Consider a simple pipeline
+ consisting of a single stage, which writes to a file. When you
+ write to the pipeline (iobuf_writebyte or iobuf_write), the data
+ is first stored in this buffer. Only when the buffer is full or
+ you call iobuf_flush() is FILTER actually called and the data
+ written to the file.
+
+ For an input pipeline (IOBUF_INPUT), this is the data that has
+ been read from this filter, but not yet been read from the
+ preceding filter (or the user, if this filter is the head of the
+ pipeline). Again, consider a simple pipeline consisting of a
+ single stage. This stage reads from a file. If you read a
+ single byte (iobuf_get) and the buffer is empty, then FILTER is
+ called to fill the buffer. In this case, a single byte is not
+ requested, but the whole buffer is filled (if possible). */
struct
{
- size_t size; /* Allocated size */
- size_t start; /* Number of invalid bytes at the
- begin of the buffer */
- size_t len; /* Currently filled to this size */
+ /* Size of the buffer. */
+ size_t size;
+ /* Number of bytes at the beginning of the buffer that have
+ already been consumed. (In other words: the index of the first
+ byte that hasn't been consumed.) This is only non-zero for
+ input filters. */
+ size_t start;
+ /* The number of bytes in the buffer including any bytes that have
+ been consumed. */
+ size_t len;
+ /* The buffer itself. */
byte *buf;
} d;
+ /* When FILTER is called to read some data, it may read some data
+ and then return EOF. We can't return the EOF immediately.
+ Instead, we note that we observed the EOF and when the buffer is
+ finally empty, we return the EOF. */
int filter_eof;
+ /* Like filter_eof, when FILTER is called to read some data, it may
+ read some data and then return an error. We can't return the
+ error (in the form of an EOF) immediately. Instead, we note that
+ we observed the error and when the buffer is finally empty, we
+ return the EOF. */
int error;
+
+ /* The callback function to read data from the filter, etc. See
+ iobuf_filter_push for details. */
int (*filter) (void *opaque, int control,
iobuf_t chain, byte * buf, size_t * len);
- void *filter_ov; /* Value for opaque */
+ /* An opaque pointer that can be used for local filter state. This
+ is passed as the first parameter to FILTER. */
+ void *filter_ov;
+ /* Whether the iobuf code should free(filter_ov) when destroying the
+ filter. */
int filter_ov_owner;
+
+ /* When using iobuf_open, iobuf_create, iobuf_openrw to open a file,
+ the file's name is saved here. This is used to delete the file
+ when an output pipeline (IOBUF_OUPUT) is canceled
+ (iobuf_cancel). */
char *real_fname;
- iobuf_t chain; /* Next iobuf used for i/o if any
- (passed to filter) */
- int no, subno;
+
+ /* The next filter in the pipeline. */
+ iobuf_t chain;
+
+ /* This field is for debugging. Each time a filter is allocated
+ (via iobuf_alloc()), a monotonically increasing counter is
+ incremented and this field is set to the new value. This field
+ should only be accessed via the iobuf_io macro. */
+ int no;
+
+ /* The number of filters in the pipeline following (not including)
+ this one. When you call iobuf_push_filter or iobuf_push_filter2,
+ this value is used to check the length of the pipeline if the
+ pipeline already contains 65 stages then these functions fail.
+ This amount of nesting typically indicates corrupted data or an
+ active denial of service attack. */
+ int subno;
};
#ifndef EXTERN_UNLESS_MAIN_MODULE
@@ -113,78 +254,350 @@ struct iobuf_struct
#endif
EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode;
+/* Whether iobuf_open, iobuf_create and iobuf_is_pipefilename
+ recognize special filenames. Special filenames are of the form
+ "-&nnnn" where n is a positive integer. The integer corresponds to
+ a file descriptor. Note: these functions always recognize the
+ special filename '-', which corresponds to standard input. */
void iobuf_enable_special_filenames (int yes);
+
+/* Returns whether the specified filename corresponds to a pipe. In
+ particular, this function checks if FNAME is "-" and, if special
+ filenames are enabled (see iobuf_enable_special_filenames), whether
+ FNAME is a special filename. */
int iobuf_is_pipe_filename (const char *fname);
+
+/* Allocate a new filter. This filter doesn't have a function
+ assigned to it. Thus you need to manually set IOBUF->FILTER and
+ IOBUF->FILTER_OV, if required. This function is intended to help
+ create a new primary source or primary sink, i.e., the last filter
+ in the pipeline.
+
+ USE is IOBUF_INPUT, IOBUF_OUTPUT or IOBUF_TEMP.
+
+ BUFSIZE is the desired internal buffer size (that is, the size of
+ the typical read / write request). */
iobuf_t iobuf_alloc (int use, size_t bufsize);
+
+/* Create an output filter that simply buffers data written to it.
+ This is useful for collecting data for later processing. The
+ buffer can be written to in the usual way (iobuf_write, etc.). The
+ data can later be extracted using iobuf_write_temp() or
+ iobuf_temp_to_buffer(). */
iobuf_t iobuf_temp (void);
+
+/* Create an input filter that contains some data for reading. */
iobuf_t iobuf_temp_with_content (const char *buffer, size_t length);
+
+/* Create an input file filter that reads from a file. If FNAME is
+ '-', reads from stdin. If special filenames are enabled
+ (iobuf_enable_special_filenames), then interprets special
+ filenames. */
iobuf_t iobuf_open (const char *fname);
+
+/* Create an output file filter that writes to a file. If FNAME is
+ NULL or '-', writes to stdout. If special filenames are enabled
+ (iobuf_enable_special_filenames), then interprets special
+ filenames. If FNAME is not NULL, '-' or a special filename, the
+ file is opened for writing. If the file exists, it is truncated.
+ If MODE700 is TRUE, the file is created with mode 600. Otherwise,
+ mode 666 is used. */
+iobuf_t iobuf_create (const char *fname, int mode700);
+
+/* Create an output file filter that writes to a specified file.
+ Neither '-' nor special file names are recognized. */
+iobuf_t iobuf_openrw (const char *fname);
+
+/* Create a file filter using an existing file descriptor. If MODE
+ contains the letter 'w', creates an output filter. Otherwise,
+ creates an input filter. Note: MODE must reflect the file
+ descriptors actual mode! When the filter is destroyed, the file
+ descriptor is closed. */
iobuf_t iobuf_fdopen (int fd, const char *mode);
+
+/* Like iobuf_fdopen, but doesn't close the file descriptor when the
+ filter is destroyed. */
iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
+
+/* Create a filter using an existing estream. If MODE contains the
+ letter 'w', creates an output filter. Otherwise, creates an input
+ filter. If KEEP_OPEN is TRUE, then the stream is not closed when
+ the filter is destroyed. Otherwise, the stream is closed when the
+ filter is destroyed. */
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open);
+
+/* Create a filter using an existing socket. On Windows creates a
+ special socket filter. On non-Windows systems simply, this simply
+ calls iobuf_fdopen. */
iobuf_t iobuf_sockopen (int fd, const char *mode);
-iobuf_t iobuf_create (const char *fname, int mode700);
-iobuf_t iobuf_openrw (const char *fname);
+
+/* Set various options / perform different actions on a PIPELINE. See
+ the IOBUF_IOCTL_* macros above. */
int iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval);
+
+/* Close a pipeline. The filters in the pipeline are first flushed
+ using iobuf_flush, if they are output filters, and then
+ IOBUFCTRL_FREE is called on each filter.
+
+ If any filter returns a non-zero value in response to the
+ IOBUFCTRL_FREE, that first such non-zero value is returned. Note:
+ processing is not aborted in this case. If all filters are freed
+ successfully, 0 is returned. */
int iobuf_close (iobuf_t iobuf);
+
+/* Calls IOBUFCTRL_CANCEL on each filter in the pipeline. Then calls
+ io_close() on the pipeline. Finally, if the pipeline is an output
+ pipeline, deletes the file. Returns the result of calling
+ iobuf_close on the pipeline. */
int iobuf_cancel (iobuf_t iobuf);
+/* Add a new filter to the front of a pipeline. A is the head of the
+ pipeline. F is the filter implementation. OV is an opaque pointer
+ that is passed to F and is normally used to hold any internal
+ state, such as a file pointer.
+
+ Note: you may only maintain a reference to an iobuf_t as a
+ reference to the head of the pipeline. That is, don't think about
+ setting a pointer in OV to point to the filter's iobuf_t. This is
+ because when we add a new filter to a pipeline, we memcpy the state
+ in A into new buffer. This has the advantage that there is no need
+ to update any references to the pipeline when a filter is added or
+ removed, but it also means that a filter's state moves around in
+ memory.
+
+ The behavior of the filter function is determined by the value of
+ the control parameter:
+
+ IOBUFCTRL_INIT: Called this value just before the filter is
+ linked into the pipeline. This can be used to initialize
+ internal data structures.
+
+ IOBUFCTRL_FREE: Called with this value just before the filter is
+ removed from the pipeline. Normally used to release internal
+ data structures, close a file handle, etc.
+
+ IOBUFCTRL_UNDERFLOW: Called with this value to fill the passed
+ buffer with more data. *LEN is the size of the buffer. Before
+ returning, it should be set to the number of bytes which were
+ written into the buffer. The function must return 0 to
+ indicate success, -1 on EOF and a GPG_ERR_xxxxx code for any
+ error.
+
+ Note: this function may both return data and indicate an error
+ or EOF. In this case, it simply writes the data to BUF, sets
+ *LEN and returns the appropriate return code. The implication
+ is that if an error occurs and no data has yet been written, it
+ is essential that *LEN be set to 0!
+
+ IOBUFCTRL_FLUSH: Called with this value to write out any
+ collected data. *LEN is the number of bytes in BUF that need
+ to be written out. Returns 0 on success and a GPG_ERR_* code
+ otherwise. *LEN must be set to the number of bytes that were
+ written out.
+
+ IOBUFCTRL_CANCEL: Called with this value when iobuf_cancel() is
+ called on the pipeline.
+
+ IOBUFCTRL_DESC: Called with this value to get a human-readable
+ description of the filter. * (char **) BUF should set to the
+ NUL-terminated string. Note: you need to keep track of this
+ value and, if necessary, free it when the filter function is
+ called with control set to IOBUFCTRL_FREE.
+ */
int iobuf_push_filter (iobuf_t a, int (*f) (void *opaque, int control,
- iobuf_t chain, byte * buf,
- size_t * len), void *ov);
+ iobuf_t chain, byte * buf,
+ size_t * len), void *ov);
+/* This variant of iobuf_push_filter allows the called to indicate
+ that OV should be freed when this filter is freed. That is, if
+ REL_OV is TRUE, then when the filter is popped or freed OV will be
+ freed after the filter function is called with control set to
+ IOBUFCTRL_FREE. */
int iobuf_push_filter2 (iobuf_t a,
int (*f) (void *opaque, int control, iobuf_t chain,
byte * buf, size_t * len), void *ov,
int rel_ov);
+
+/* Used for debugging. Prints out the chain using log_debug if
+ IOBUF_DEBUG_MODE is not 0. */
+int iobuf_print_chain (iobuf_t a);
+
+/* Indicate that some error occured on the specified filter. */
#define iobuf_set_error(a) do { (a)->error = 1; } while(0)
+
+/* Return any pending error on filter A. */
#define iobuf_error(a) ((a)->error)
+/* Limit the amount of additional data that may be read from the
+ filter. That is, if you've already read 100 bytes from A and you
+ set the limit to 50, then you can read up to an additional 50 bytes
+ (i.e., a total of 150 bytes) before EOF is forcefully returned.
+ Setting NLIMIT to 0 removes any active limit.
+
+ Note: using iobuf_seek removes any currently enforced limit! */
void iobuf_set_limit (iobuf_t a, off_t nlimit);
+/* Returns the number of bytes that have been read from the pipeline.
+ Note: the result is undefined for IOBUF_OUTPUT and IOBUF_TEMP
+ pipelines! */
off_t iobuf_tell (iobuf_t a);
+
+/* There are two cases:
+
+ - If A is an INPUT or OUTPUT pipeline, then the last filter in the
+ pipeline is found. If that is not a file filter, -1 is returned.
+ Otherwise, an fseek(..., SEEK_SET) is performed on the file
+ descriptor.
+
+ - If A is a TEMP pipeline and the *first* (and thus only filter) is
+ a TEMP filter, then the "file position" is effectively unchanged.
+ That is, data is appended to the buffer and the seek does not
+ cause the size of the buffer to grow.
+
+ If no error occured, then any limit previous set by
+ iobuf_set_limit() is cleared. Further, any error on the filter
+ (the file filter or the temp filter) is cleared.
+
+ Returns 0 on success and -1 if an error occurs. */
int iobuf_seek (iobuf_t a, off_t newpos);
+/* Read a single byte. If a filter has no more data, returns -1 to
+ indicate the EOF. Generally, you don't want to use this function,
+ but instead prefer the iobuf_get macro, which is faster if there is
+ data in the internal buffer. */
int iobuf_readbyte (iobuf_t a);
+
+/* Get a byte from the iobuf; must check for eof prior to this
+ function. This function returns values in the range 0 .. 255 or -1
+ to indicate EOF. iobuf_get_noeof() does not return -1 to indicate
+ EOF, but masks the returned value to be in the range 0 .. 255. */
+#define iobuf_get(a) \
+ ( ((a)->nofast || (a)->d.start >= (a)->d.len )? \
+ iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
+#define iobuf_get_noeof(a) (iobuf_get((a))&0xff)
+
+/* Fill BUF with up to BUFLEN bytes. If a filter has no more data,
+ returns -1 to indicate the EOF. Otherwise returns the number of
+ bytes read. */
int iobuf_read (iobuf_t a, void *buf, unsigned buflen);
+
+/* Read a line of input (including the '\n') from the pipeline.
+
+ The semantics are the same as for fgets(), but if the buffer is too
+ short a larger one will be allocated up to *MAX_LENGTH and the end
+ of the line except the trailing '\n' discarded. (Thus,
+ *ADDR_OF_BUFFER must be allocated using malloc().) If the buffer
+ is enlarged, then *LENGTH_OF_BUFFER will be updated to reflect the
+ new size. If the line is truncated, then *MAX_LENGTH will be set
+ to 0. If *ADDR_OF_BUFFER is NULL, a buffer is allocated using
+ malloc().
+
+ A line is considered a byte stream ending in a '\n'. Returns the
+ number of characters written to the buffer (i.e., excluding any
+ discarded characters due to truncation). Thus, use this instead of
+ strlen(buffer) to determine the length of the string as this is
+ unreliable if the input contains NUL characters.
+
+ EOF is indicated by a line of length zero.
+
+ The last LF may be missing due to an EOF. */
unsigned iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
unsigned *length_of_buffer, unsigned *max_length);
+
+/* Read up to BUFLEN bytes from pipeline A. Note: this function can't
+ return more than the pipeline's internal buffer size. The return
+ value is the number of bytes actually written to BUF. If the
+ filter returns EOF, then this function returns -1.
+
+ This function does not clear any pending EOF. That is, if the
+ pipeline consists of two filters and the first one returns EOF
+ during the peek, then the subsequent iobuf_read* will still return
+ EOF before returning the data from the second filter. */
int iobuf_peek (iobuf_t a, byte * buf, unsigned buflen);
+
+/* Write a byte to the pipeline. Returns 0 on success and an error
+ code otherwise. */
int iobuf_writebyte (iobuf_t a, unsigned c);
+
+/* Alias for iobuf_writebyte. */
+#define iobuf_put(a,c) iobuf_writebyte(a,c)
+
+/* Write a sequence of bytes to the pipeline. Returns 0 on success
+ and an error code otherwise. */
int iobuf_write (iobuf_t a, const void *buf, unsigned buflen);
+
+/* Write a string (not including the NUL terminator) to the pipeline.
+ Returns 0 on success and an error code otherwise. */
int iobuf_writestr (iobuf_t a, const char *buf);
+/* Flushes the pipeline removing all filters but the sink (the last
+ filter) in the process. */
void iobuf_flush_temp (iobuf_t temp);
-int iobuf_write_temp (iobuf_t a, iobuf_t temp);
+
+/* Flushes the pipeline SOURCE removing all filters but the sink (the
+ last filter) in the process (i.e., it calls
+ iobuf_flush_temp(source)) and then writes the data to the pipeline
+ DEST. Note: this doesn't free (iobuf_close()) SOURCE. Both SOURCE
+ and DEST must be output pipelines. */
+int iobuf_write_temp (iobuf_t dest, iobuf_t source);
+
+/* Flushes each filter in the pipeline (i.e., sends any buffered data
+ to the filter by calling IOBUFCTRL_FLUSH). Then, copies up to the
+ first BUFLEN bytes from the last filter's internal buffer (which
+ will only be non-empty if it is a temp filter) to the buffer
+ BUFFER. Returns the number of bytes actually copied. */
size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen);
+/* Return the size of any underlying file. This only works with
+ file_filter based pipelines.
+
+ On Win32, it is sometimes not possible to determine the size of
+ files larger than 4GB. In this case, *OVERFLOW (if not NULL) is
+ set to 1. Otherwise, *OVERFLOW is set to 0. */
off_t iobuf_get_filelength (iobuf_t a, int *overflow);
#define IOBUF_FILELENGTH_LIMIT 0xffffffff
+
+/* Return the file descriptor designating the underlying file. This
+ only works with file_filter based pipelines. */
int iobuf_get_fd (iobuf_t a);
+
+/* Return the real filename, if available. This only supports
+ pipelines that end in file filters. Returns NULL if not
+ available. */
const char *iobuf_get_real_fname (iobuf_t a);
+
+/* Return the filename or a description thereof. For instance, for
+ iobuf_open("-"), this will return "[stdin]". This only supports
+ pipelines that end in file filters. Returns NULL if not
+ available. */
const char *iobuf_get_fname (iobuf_t a);
+
+/* Like iobuf_getfname, but instead of returning NULL if no
+ description is available, return "[?]". */
const char *iobuf_get_fname_nonnull (iobuf_t a);
+/* Pushes a filter on the pipeline that interprets the datastream as
+ an OpenPGP data block whose length is encoded using partial body
+ length headers (see Section 4.2.2.4 of RFC 4880). Concretely, it
+ just returns / writes the data and finishes the packet with an
+ EOF. */
void iobuf_set_partial_block_mode (iobuf_t a, size_t len);
-void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
-
+/* If PARTIAL is set, then read from the pipeline until the first EOF
+ is returned.
-/* Get a byte from the iobuf; must check for eof prior to this
- * function. This function returns values in the range 0 .. 255 or -1
- * to indicate EOF. iobuf_get_noeof() does not return -1 to indicate
- * EOF, but masks the returned value to be in the range 0 .. 255.
- */
-#define iobuf_get(a) \
- ( ((a)->nofast || (a)->d.start >= (a)->d.len )? \
- iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
-#define iobuf_get_noeof(a) (iobuf_get((a))&0xff)
+ If PARTIAL is 0, then read up to N bytes or until the first EOF is
+ returned.
-/* write a byte to the iobuf and return true on write error
- * This macro does only write the low order byte
- */
-#define iobuf_put(a,c) iobuf_writebyte(a,c)
+ Recall: a filter can return EOF. In this case, it and all
+ preceding filters are popped from the pipeline and the next read is
+ from the following filter (which may or may not return EOF). */
+void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
#define iobuf_where(a) "[don't know]"
+
+/* Each time a filter is allocated (via iobuf_alloc()), a
+ monotonically increasing counter is incremented and this field is
+ set to the new value. This macro returns that number. */
#define iobuf_id(a) ((a)->no)
#define iobuf_get_temp_buffer(a) ( (a)->d.buf )