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 @@ -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); -iobuf_t iobuf_fdopen (int fd, const char *mode); -iobuf_t iobuf_fdopen_nc (int fd, const char *mode); -iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open); -iobuf_t iobuf_sockopen (int fd, const char *mode); + +/* 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); + +/* 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); -int iobuf_read (iobuf_t a, void *buf, unsigned buflen); -unsigned iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, - unsigned *length_of_buffer, unsigned *max_length); -int iobuf_peek (iobuf_t a, byte * buf, unsigned buflen); -int iobuf_writebyte (iobuf_t a, unsigned c); -int iobuf_write (iobuf_t a, const void *buf, unsigned buflen); -int iobuf_writestr (iobuf_t a, const char *buf); - -void iobuf_flush_temp (iobuf_t temp); -int iobuf_write_temp (iobuf_t a, iobuf_t temp); -size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen); - -off_t iobuf_get_filelength (iobuf_t a, int *overflow); -#define IOBUF_FILELENGTH_LIMIT 0xffffffff -int iobuf_get_fd (iobuf_t a); -const char *iobuf_get_real_fname (iobuf_t a); -const char *iobuf_get_fname (iobuf_t a); -const char *iobuf_get_fname_nonnull (iobuf_t a); - -void iobuf_set_partial_block_mode (iobuf_t a, size_t len); - -void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial); - /* 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. - */ + 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) -/* write a byte to the iobuf and return true on write error - * This macro does only write the low order byte - */ +/* 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); + +/* 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); + +/* If PARTIAL is set, then read from the pipeline until the first EOF + is returned. + + If PARTIAL is 0, then read up to N bytes or until the first EOF is + returned. + + 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 )