summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/buffer.c')
-rw-r--r--contrib/cvs/src/buffer.c1980
1 files changed, 0 insertions, 1980 deletions
diff --git a/contrib/cvs/src/buffer.c b/contrib/cvs/src/buffer.c
deleted file mode 100644
index db2bea0..0000000
--- a/contrib/cvs/src/buffer.c
+++ /dev/null
@@ -1,1980 +0,0 @@
-/*
- * Copyright (C) 1996-2005 The Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/* Code for the buffer data structure. */
-
-/* $FreeBSD$ */
-
-#include <assert.h>
-#include "cvs.h"
-#include "buffer.h"
-
-#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
-
-#ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-#else
-# include <sys/socket.h>
-#endif
-
-/* OS/2 doesn't have EIO. FIXME: this whole notion of turning
- a different error into EIO strikes me as pretty dubious. */
-#if !defined (EIO)
-#define EIO EBADPOS
-#endif
-
-/* Linked list of available buffer_data structures. */
-static struct buffer_data *free_buffer_data;
-
-/* Local functions. */
-static void buf_default_memory_error PROTO ((struct buffer *));
-static void allocate_buffer_datas PROTO((void));
-static struct buffer_data *get_buffer_data PROTO((void));
-
-/* Initialize a buffer structure. */
-
-struct buffer *
-buf_initialize (input, output, flush, block, shutdown, memory, closure)
- int (*input) PROTO((void *, char *, int, int, int *));
- int (*output) PROTO((void *, const char *, int, int *));
- int (*flush) PROTO((void *));
- int (*block) PROTO((void *, int));
- int (*shutdown) PROTO((struct buffer *));
- void (*memory) PROTO((struct buffer *));
- void *closure;
-{
- struct buffer *buf;
-
- buf = (struct buffer *) xmalloc (sizeof (struct buffer));
- buf->data = NULL;
- buf->last = NULL;
- buf->nonblocking = 0;
- buf->input = input;
- buf->output = output;
- buf->flush = flush;
- buf->block = block;
- buf->shutdown = shutdown;
- buf->memory_error = memory ? memory : buf_default_memory_error;
- buf->closure = closure;
- return buf;
-}
-
-/* Free a buffer structure. */
-
-void
-buf_free (buf)
- struct buffer *buf;
-{
- if (buf->closure != NULL)
- {
- free (buf->closure);
- buf->closure = NULL;
- }
- if (buf->data != NULL)
- {
- buf->last->next = free_buffer_data;
- free_buffer_data = buf->data;
- }
- free (buf);
-}
-
-/* Initialize a buffer structure which is not to be used for I/O. */
-
-struct buffer *
-buf_nonio_initialize (memory)
- void (*memory) PROTO((struct buffer *));
-{
- return (buf_initialize
- ((int (*) PROTO((void *, char *, int, int, int *))) NULL,
- (int (*) PROTO((void *, const char *, int, int *))) NULL,
- (int (*) PROTO((void *))) NULL,
- (int (*) PROTO((void *, int))) NULL,
- (int (*) PROTO((struct buffer *))) NULL,
- memory,
- (void *) NULL));
-}
-
-/* Default memory error handler. */
-
-static void
-buf_default_memory_error (buf)
- struct buffer *buf;
-{
- error (1, 0, "out of memory");
-}
-
-/* Allocate more buffer_data structures. */
-
-static void
-allocate_buffer_datas ()
-{
- struct buffer_data *alc;
- char *space;
- int i;
-
- /* Allocate buffer_data structures in blocks of 16. */
-#define ALLOC_COUNT (16)
-
- alc = xmalloc (ALLOC_COUNT * sizeof (struct buffer_data));
- space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
- if (!space)
- {
- free (alc);
- return;
- }
- for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE)
- {
- alc->next = free_buffer_data;
- free_buffer_data = alc;
- alc->text = space;
- }
-}
-
-/* Get a new buffer_data structure. */
-
-static struct buffer_data *
-get_buffer_data ()
-{
- struct buffer_data *ret;
-
- if (free_buffer_data == NULL)
- {
- allocate_buffer_datas ();
- if (free_buffer_data == NULL)
- return NULL;
- }
-
- ret = free_buffer_data;
- free_buffer_data = ret->next;
- return ret;
-}
-
-
-
-/* See whether a buffer and its file descriptor is empty. */
-int
-buf_empty (buf)
- struct buffer *buf;
-{
- /* Try and read any data on the file descriptor first.
- * We already know the descriptor is non-blocking.
- */
- buf_input_data (buf, NULL);
- return buf_empty_p (buf);
-}
-
-
-
-/* See whether a buffer is empty. */
-int
-buf_empty_p (buf)
- struct buffer *buf;
-{
- struct buffer_data *data;
-
- for (data = buf->data; data != NULL; data = data->next)
- if (data->size > 0)
- return 0;
- return 1;
-}
-
-
-
-#ifdef SERVER_FLOWCONTROL
-/*
- * Count how much data is stored in the buffer..
- * Note that each buffer is a xmalloc'ed chunk BUFFER_DATA_SIZE.
- */
-
-int
-buf_count_mem (buf)
- struct buffer *buf;
-{
- struct buffer_data *data;
- int mem = 0;
-
- for (data = buf->data; data != NULL; data = data->next)
- mem += BUFFER_DATA_SIZE;
-
- return mem;
-}
-#endif /* SERVER_FLOWCONTROL */
-
-/* Add data DATA of length LEN to BUF. */
-
-void
-buf_output (buf, data, len)
- struct buffer *buf;
- const char *data;
- int len;
-{
- if (buf->data != NULL
- && (((buf->last->text + BUFFER_DATA_SIZE)
- - (buf->last->bufp + buf->last->size))
- >= len))
- {
- memcpy (buf->last->bufp + buf->last->size, data, len);
- buf->last->size += len;
- return;
- }
-
- while (1)
- {
- struct buffer_data *newdata;
-
- newdata = get_buffer_data ();
- if (newdata == NULL)
- {
- (*buf->memory_error) (buf);
- return;
- }
-
- if (buf->data == NULL)
- buf->data = newdata;
- else
- buf->last->next = newdata;
- newdata->next = NULL;
- buf->last = newdata;
-
- newdata->bufp = newdata->text;
-
- if (len <= BUFFER_DATA_SIZE)
- {
- newdata->size = len;
- memcpy (newdata->text, data, len);
- return;
- }
-
- newdata->size = BUFFER_DATA_SIZE;
- memcpy (newdata->text, data, BUFFER_DATA_SIZE);
-
- data += BUFFER_DATA_SIZE;
- len -= BUFFER_DATA_SIZE;
- }
-
- /*NOTREACHED*/
-}
-
-/* Add a '\0' terminated string to BUF. */
-
-void
-buf_output0 (buf, string)
- struct buffer *buf;
- const char *string;
-{
- buf_output (buf, string, strlen (string));
-}
-
-/* Add a single character to BUF. */
-
-void
-buf_append_char (buf, ch)
- struct buffer *buf;
- int ch;
-{
- if (buf->data != NULL
- && (buf->last->text + BUFFER_DATA_SIZE
- != buf->last->bufp + buf->last->size))
- {
- *(buf->last->bufp + buf->last->size) = ch;
- ++buf->last->size;
- }
- else
- {
- char b;
-
- b = ch;
- buf_output (buf, &b, 1);
- }
-}
-
-/*
- * Send all the output we've been saving up. Returns 0 for success or
- * errno code. If the buffer has been set to be nonblocking, this
- * will just write until the write would block.
- */
-
-int
-buf_send_output (buf)
- struct buffer *buf;
-{
- if (buf->output == NULL)
- abort ();
-
- while (buf->data != NULL)
- {
- struct buffer_data *data;
-
- data = buf->data;
-
- if (data->size > 0)
- {
- int status, nbytes;
-
- status = (*buf->output) (buf->closure, data->bufp, data->size,
- &nbytes);
- if (status != 0)
- {
- /* Some sort of error. Discard the data, and return. */
-
- buf->last->next = free_buffer_data;
- free_buffer_data = buf->data;
- buf->data = NULL;
- buf->last = NULL;
-
- return status;
- }
-
- if (nbytes != data->size)
- {
- /* Not all the data was written out. This is only
- permitted in nonblocking mode. Adjust the buffer,
- and return. */
-
- assert (buf->nonblocking);
-
- data->size -= nbytes;
- data->bufp += nbytes;
-
- return 0;
- }
- }
-
- buf->data = data->next;
- data->next = free_buffer_data;
- free_buffer_data = data;
- }
-
- buf->last = NULL;
-
- return 0;
-}
-
-/*
- * Flush any data queued up in the buffer. If BLOCK is nonzero, then
- * if the buffer is in nonblocking mode, put it into blocking mode for
- * the duration of the flush. This returns 0 on success, or an error
- * code.
- */
-
-int
-buf_flush (buf, block)
- struct buffer *buf;
- int block;
-{
- int nonblocking;
- int status;
-
- if (buf->flush == NULL)
- abort ();
-
- nonblocking = buf->nonblocking;
- if (nonblocking && block)
- {
- status = set_block (buf);
- if (status != 0)
- return status;
- }
-
- status = buf_send_output (buf);
- if (status == 0)
- status = (*buf->flush) (buf->closure);
-
- if (nonblocking && block)
- {
- int blockstat;
-
- blockstat = set_nonblock (buf);
- if (status == 0)
- status = blockstat;
- }
-
- return status;
-}
-
-/*
- * Set buffer BUF to nonblocking I/O. Returns 0 for success or errno
- * code.
- */
-
-int
-set_nonblock (buf)
- struct buffer *buf;
-{
- int status;
-
- if (buf->nonblocking)
- return 0;
- if (buf->block == NULL)
- abort ();
- status = (*buf->block) (buf->closure, 0);
- if (status != 0)
- return status;
- buf->nonblocking = 1;
- return 0;
-}
-
-/*
- * Set buffer BUF to blocking I/O. Returns 0 for success or errno
- * code.
- */
-
-int
-set_block (buf)
- struct buffer *buf;
-{
- int status;
-
- if (! buf->nonblocking)
- return 0;
- if (buf->block == NULL)
- abort ();
- status = (*buf->block) (buf->closure, 1);
- if (status != 0)
- return status;
- buf->nonblocking = 0;
- return 0;
-}
-
-/*
- * Send a character count and some output. Returns errno code or 0 for
- * success.
- *
- * Sending the count in binary is OK since this is only used on a pipe
- * within the same system.
- */
-
-int
-buf_send_counted (buf)
- struct buffer *buf;
-{
- int size;
- struct buffer_data *data;
-
- size = 0;
- for (data = buf->data; data != NULL; data = data->next)
- size += data->size;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- (*buf->memory_error) (buf);
- return ENOMEM;
- }
-
- data->next = buf->data;
- buf->data = data;
- if (buf->last == NULL)
- buf->last = data;
-
- data->bufp = data->text;
- data->size = sizeof (int);
-
- *((int *) data->text) = size;
-
- return buf_send_output (buf);
-}
-
-/*
- * Send a special count. COUNT should be negative. It will be
- * handled speciallyi by buf_copy_counted. This function returns 0 or
- * an errno code.
- *
- * Sending the count in binary is OK since this is only used on a pipe
- * within the same system.
- */
-
-int
-buf_send_special_count (buf, count)
- struct buffer *buf;
- int count;
-{
- struct buffer_data *data;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- (*buf->memory_error) (buf);
- return ENOMEM;
- }
-
- data->next = buf->data;
- buf->data = data;
- if (buf->last == NULL)
- buf->last = data;
-
- data->bufp = data->text;
- data->size = sizeof (int);
-
- *((int *) data->text) = count;
-
- return buf_send_output (buf);
-}
-
-/* Append a list of buffer_data structures to an buffer. */
-
-void
-buf_append_data (buf, data, last)
- struct buffer *buf;
- struct buffer_data *data;
- struct buffer_data *last;
-{
- if (data != NULL)
- {
- if (buf->data == NULL)
- buf->data = data;
- else
- buf->last->next = data;
- buf->last = last;
- }
-}
-
-/* Append the data on one buffer to another. This removes the data
- from the source buffer. */
-
-void
-buf_append_buffer (to, from)
- struct buffer *to;
- struct buffer *from;
-{
- buf_append_data (to, from->data, from->last);
- from->data = NULL;
- from->last = NULL;
-}
-
-/*
- * Copy the contents of file F into buffer_data structures. We can't
- * copy directly into an buffer, because we want to handle failure and
- * succeess differently. Returns 0 on success, or -2 if out of
- * memory, or a status code on error. Since the caller happens to
- * know the size of the file, it is passed in as SIZE. On success,
- * this function sets *RETP and *LASTP, which may be passed to
- * buf_append_data.
- */
-
-int
-buf_read_file (f, size, retp, lastp)
- FILE *f;
- long size;
- struct buffer_data **retp;
- struct buffer_data **lastp;
-{
- int status;
-
- *retp = NULL;
- *lastp = NULL;
-
- while (size > 0)
- {
- struct buffer_data *data;
- int get;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- status = -2;
- goto error_return;
- }
-
- if (*retp == NULL)
- *retp = data;
- else
- (*lastp)->next = data;
- data->next = NULL;
- *lastp = data;
-
- data->bufp = data->text;
- data->size = 0;
-
- if (size > BUFFER_DATA_SIZE)
- get = BUFFER_DATA_SIZE;
- else
- get = size;
-
- errno = EIO;
- if (fread (data->text, get, 1, f) != 1)
- {
- status = errno;
- goto error_return;
- }
-
- data->size += get;
- size -= get;
- }
-
- return 0;
-
- error_return:
- if (*retp != NULL)
- {
- (*lastp)->next = free_buffer_data;
- free_buffer_data = *retp;
- }
- return status;
-}
-
-/*
- * Copy the contents of file F into buffer_data structures. We can't
- * copy directly into an buffer, because we want to handle failure and
- * succeess differently. Returns 0 on success, or -2 if out of
- * memory, or a status code on error. On success, this function sets
- * *RETP and *LASTP, which may be passed to buf_append_data.
- */
-
-int
-buf_read_file_to_eof (f, retp, lastp)
- FILE *f;
- struct buffer_data **retp;
- struct buffer_data **lastp;
-{
- int status;
-
- *retp = NULL;
- *lastp = NULL;
-
- while (!feof (f))
- {
- struct buffer_data *data;
- int get, nread;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- status = -2;
- goto error_return;
- }
-
- if (*retp == NULL)
- *retp = data;
- else
- (*lastp)->next = data;
- data->next = NULL;
- *lastp = data;
-
- data->bufp = data->text;
- data->size = 0;
-
- get = BUFFER_DATA_SIZE;
-
- errno = EIO;
- nread = fread (data->text, 1, get, f);
- if (nread == 0 && !feof (f))
- {
- status = errno;
- goto error_return;
- }
-
- data->size = nread;
- }
-
- return 0;
-
- error_return:
- if (*retp != NULL)
- {
- (*lastp)->next = free_buffer_data;
- free_buffer_data = *retp;
- }
- return status;
-}
-
-/* Return the number of bytes in a chain of buffer_data structures. */
-
-int
-buf_chain_length (buf)
- struct buffer_data *buf;
-{
- int size = 0;
- while (buf)
- {
- size += buf->size;
- buf = buf->next;
- }
- return size;
-}
-
-/* Return the number of bytes in a buffer. */
-
-int
-buf_length (buf)
- struct buffer *buf;
-{
- return buf_chain_length (buf->data);
-}
-
-/*
- * Read an arbitrary amount of data into an input buffer. The buffer
- * will be in nonblocking mode, and we just grab what we can. Return
- * 0 on success, or -1 on end of file, or -2 if out of memory, or an
- * error code. If COUNTP is not NULL, *COUNTP is set to the number of
- * bytes read.
- */
-
-int
-buf_input_data (buf, countp)
- struct buffer *buf;
- int *countp;
-{
- if (buf->input == NULL)
- abort ();
-
- if (countp != NULL)
- *countp = 0;
-
- while (1)
- {
- int get;
- int status, nbytes;
-
- if (buf->data == NULL
- || (buf->last->bufp + buf->last->size
- == buf->last->text + BUFFER_DATA_SIZE))
- {
- struct buffer_data *data;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- (*buf->memory_error) (buf);
- return -2;
- }
-
- if (buf->data == NULL)
- buf->data = data;
- else
- buf->last->next = data;
- data->next = NULL;
- buf->last = data;
-
- data->bufp = data->text;
- data->size = 0;
- }
-
- get = ((buf->last->text + BUFFER_DATA_SIZE)
- - (buf->last->bufp + buf->last->size));
-
- status = (*buf->input) (buf->closure,
- buf->last->bufp + buf->last->size,
- 0, get, &nbytes);
- if (status != 0)
- return status;
-
- buf->last->size += nbytes;
- if (countp != NULL)
- *countp += nbytes;
-
- if (nbytes < get)
- {
- /* If we did not fill the buffer, then presumably we read
- all the available data. */
- return 0;
- }
- }
-
- /*NOTREACHED*/
-}
-
-/*
- * Read a line (characters up to a \012) from an input buffer. (We
- * use \012 rather than \n for the benefit of non Unix clients for
- * which \n means something else). This returns 0 on success, or -1
- * on end of file, or -2 if out of memory, or an error code. If it
- * succeeds, it sets *LINE to an allocated buffer holding the contents
- * of the line. The trailing \012 is not included in the buffer. If
- * LENP is not NULL, then *LENP is set to the number of bytes read;
- * strlen may not work, because there may be embedded null bytes.
- */
-
-int
-buf_read_line (buf, line, lenp)
- struct buffer *buf;
- char **line;
- int *lenp;
-{
- if (buf->input == NULL)
- abort ();
-
- *line = NULL;
-
- while (1)
- {
- int len, finallen = 0;
- struct buffer_data *data;
- char *nl;
-
- /* See if there is a newline in BUF. */
- len = 0;
- for (data = buf->data; data != NULL; data = data->next)
- {
- nl = memchr (data->bufp, '\012', data->size);
- if (nl != NULL)
- {
- finallen = nl - data->bufp;
- len += finallen;
- break;
- }
- len += data->size;
- }
-
- /* If we found a newline, copy the line into a memory buffer,
- and remove it from BUF. */
- if (data != NULL)
- {
- char *p;
- struct buffer_data *nldata;
-
- p = xmalloc (len + 1);
- if (p == NULL)
- return -2;
- *line = p;
-
- nldata = data;
- data = buf->data;
- while (data != nldata)
- {
- struct buffer_data *next;
-
- memcpy (p, data->bufp, data->size);
- p += data->size;
- next = data->next;
- data->next = free_buffer_data;
- free_buffer_data = data;
- data = next;
- }
-
- memcpy (p, data->bufp, finallen);
- p[finallen] = '\0';
-
- data->size -= finallen + 1;
- data->bufp = nl + 1;
- buf->data = data;
-
- if (lenp != NULL)
- *lenp = len;
-
- return 0;
- }
-
- /* Read more data until we get a newline. */
- while (1)
- {
- int size, status, nbytes;
- char *mem;
-
- if (buf->data == NULL
- || (buf->last->bufp + buf->last->size
- == buf->last->text + BUFFER_DATA_SIZE))
- {
- data = get_buffer_data ();
- if (data == NULL)
- {
- (*buf->memory_error) (buf);
- return -2;
- }
-
- if (buf->data == NULL)
- buf->data = data;
- else
- buf->last->next = data;
- data->next = NULL;
- buf->last = data;
-
- data->bufp = data->text;
- data->size = 0;
- }
-
- mem = buf->last->bufp + buf->last->size;
- size = (buf->last->text + BUFFER_DATA_SIZE) - mem;
-
- /* We need to read at least 1 byte. We can handle up to
- SIZE bytes. This will only be efficient if the
- underlying communication stream does its own buffering,
- or is clever about getting more than 1 byte at a time. */
- status = (*buf->input) (buf->closure, mem, 1, size, &nbytes);
- if (status != 0)
- return status;
-
- buf->last->size += nbytes;
-
- /* Optimize slightly to avoid an unnecessary call to
- memchr. */
- if (nbytes == 1)
- {
- if (*mem == '\012')
- break;
- }
- else
- {
- if (memchr (mem, '\012', nbytes) != NULL)
- break;
- }
- }
- }
-}
-
-/*
- * Extract data from the input buffer BUF. This will read up to WANT
- * bytes from the buffer. It will set *RETDATA to point at the bytes,
- * and set *GOT to the number of bytes to be found there. Any buffer
- * call which uses BUF may change the contents of the buffer at *DATA,
- * so the data should be fully processed before any further calls are
- * made. This returns 0 on success, or -1 on end of file, or -2 if
- * out of memory, or an error code.
- */
-
-int
-buf_read_data (buf, want, retdata, got)
- struct buffer *buf;
- int want;
- char **retdata;
- int *got;
-{
- if (buf->input == NULL)
- abort ();
-
- while (buf->data != NULL && buf->data->size == 0)
- {
- struct buffer_data *next;
-
- next = buf->data->next;
- buf->data->next = free_buffer_data;
- free_buffer_data = buf->data;
- buf->data = next;
- if (next == NULL)
- buf->last = NULL;
- }
-
- if (buf->data == NULL)
- {
- struct buffer_data *data;
- int get, status, nbytes;
-
- data = get_buffer_data ();
- if (data == NULL)
- {
- (*buf->memory_error) (buf);
- return -2;
- }
-
- buf->data = data;
- buf->last = data;
- data->next = NULL;
- data->bufp = data->text;
- data->size = 0;
-
- if (want < BUFFER_DATA_SIZE)
- get = want;
- else
- get = BUFFER_DATA_SIZE;
- status = (*buf->input) (buf->closure, data->bufp, get,
- BUFFER_DATA_SIZE, &nbytes);
- if (status != 0)
- return status;
-
- data->size = nbytes;
- }
-
- *retdata = buf->data->bufp;
- if (want < buf->data->size)
- {
- *got = want;
- buf->data->size -= want;
- buf->data->bufp += want;
- }
- else
- {
- *got = buf->data->size;
- buf->data->size = 0;
- }
-
- return 0;
-}
-
-/*
- * Copy lines from an input buffer to an output buffer. This copies
- * all complete lines (characters up to a newline) from INBUF to
- * OUTBUF. Each line in OUTBUF is preceded by the character COMMAND
- * and a space.
- */
-
-void
-buf_copy_lines (outbuf, inbuf, command)
- struct buffer *outbuf;
- struct buffer *inbuf;
- int command;
-{
- while (1)
- {
- struct buffer_data *data;
- struct buffer_data *nldata;
- char *nl;
- int len;
-
- /* See if there is a newline in INBUF. */
- nldata = NULL;
- nl = NULL;
- for (data = inbuf->data; data != NULL; data = data->next)
- {
- nl = memchr (data->bufp, '\n', data->size);
- if (nl != NULL)
- {
- nldata = data;
- break;
- }
- }
-
- if (nldata == NULL)
- {
- /* There are no more lines in INBUF. */
- return;
- }
-
- /* Put in the command. */
- buf_append_char (outbuf, command);
- buf_append_char (outbuf, ' ');
-
- if (inbuf->data != nldata)
- {
- /*
- * Simply move over all the buffers up to the one containing
- * the newline.
- */
- for (data = inbuf->data; data->next != nldata; data = data->next)
- ;
- data->next = NULL;
- buf_append_data (outbuf, inbuf->data, data);
- inbuf->data = nldata;
- }
-
- /*
- * If the newline is at the very end of the buffer, just move
- * the buffer onto OUTBUF. Otherwise we must copy the data.
- */
- len = nl + 1 - nldata->bufp;
- if (len == nldata->size)
- {
- inbuf->data = nldata->next;
- if (inbuf->data == NULL)
- inbuf->last = NULL;
-
- nldata->next = NULL;
- buf_append_data (outbuf, nldata, nldata);
- }
- else
- {
- buf_output (outbuf, nldata->bufp, len);
- nldata->bufp += len;
- nldata->size -= len;
- }
- }
-}
-
-/*
- * Copy counted data from one buffer to another. The count is an
- * integer, host size, host byte order (it is only used across a
- * pipe). If there is enough data, it should be moved over. If there
- * is not enough data, it should remain on the original buffer. A
- * negative count is a special case. if one is seen, *SPECIAL is set
- * to the (negative) count value and no additional data is gathered
- * from the buffer; normally *SPECIAL is set to 0. This function
- * returns the number of bytes it needs to see in order to actually
- * copy something over.
- */
-
-int
-buf_copy_counted (outbuf, inbuf, special)
- struct buffer *outbuf;
- struct buffer *inbuf;
- int *special;
-{
- *special = 0;
-
- while (1)
- {
- struct buffer_data *data;
- int need;
- union
- {
- char intbuf[sizeof (int)];
- int i;
- } u;
- char *intp;
- int count;
- struct buffer_data *start;
- int startoff;
- struct buffer_data *stop;
- int stopwant;
-
- /* See if we have enough bytes to figure out the count. */
- need = sizeof (int);
- intp = u.intbuf;
- for (data = inbuf->data; data != NULL; data = data->next)
- {
- if (data->size >= need)
- {
- memcpy (intp, data->bufp, need);
- break;
- }
- memcpy (intp, data->bufp, data->size);
- intp += data->size;
- need -= data->size;
- }
- if (data == NULL)
- {
- /* We don't have enough bytes to form an integer. */
- return need;
- }
-
- count = u.i;
- start = data;
- startoff = need;
-
- if (count < 0)
- {
- /* A negative COUNT is a special case meaning that we
- don't need any further information. */
- stop = start;
- stopwant = 0;
- }
- else
- {
- /*
- * We have an integer in COUNT. We have gotten all the
- * data from INBUF in all buffers before START, and we
- * have gotten STARTOFF bytes from START. See if we have
- * enough bytes remaining in INBUF.
- */
- need = count - (start->size - startoff);
- if (need <= 0)
- {
- stop = start;
- stopwant = count;
- }
- else
- {
- for (data = start->next; data != NULL; data = data->next)
- {
- if (need <= data->size)
- break;
- need -= data->size;
- }
- if (data == NULL)
- {
- /* We don't have enough bytes. */
- return need;
- }
- stop = data;
- stopwant = need;
- }
- }
-
- /*
- * We have enough bytes. Free any buffers in INBUF before
- * START, and remove STARTOFF bytes from START, so that we can
- * forget about STARTOFF.
- */
- start->bufp += startoff;
- start->size -= startoff;
-
- if (start->size == 0)
- start = start->next;
-
- if (stop->size == stopwant)
- {
- stop = stop->next;
- stopwant = 0;
- }
-
- while (inbuf->data != start)
- {
- data = inbuf->data;
- inbuf->data = data->next;
- data->next = free_buffer_data;
- free_buffer_data = data;
- }
-
- /* If COUNT is negative, set *SPECIAL and get out now. */
- if (count < 0)
- {
- *special = count;
- return 0;
- }
-
- /*
- * We want to copy over the bytes from START through STOP. We
- * only want STOPWANT bytes from STOP.
- */
-
- if (start != stop)
- {
- /* Attach the buffers from START through STOP to OUTBUF. */
- for (data = start; data->next != stop; data = data->next)
- ;
- inbuf->data = stop;
- data->next = NULL;
- buf_append_data (outbuf, start, data);
- }
-
- if (stopwant > 0)
- {
- buf_output (outbuf, stop->bufp, stopwant);
- stop->bufp += stopwant;
- stop->size -= stopwant;
- }
- }
-
- /*NOTREACHED*/
-}
-
-/* Shut down a buffer. This returns 0 on success, or an errno code. */
-
-int
-buf_shutdown (buf)
- struct buffer *buf;
-{
- if (buf->shutdown)
- return (*buf->shutdown) (buf);
- return 0;
-}
-
-
-
-/* The simplest type of buffer is one built on top of a stdio FILE.
- For simplicity, and because it is all that is required, we do not
- implement setting this type of buffer into nonblocking mode. The
- closure field is just a FILE *. */
-
-static int stdio_buffer_input PROTO((void *, char *, int, int, int *));
-static int stdio_buffer_output PROTO((void *, const char *, int, int *));
-static int stdio_buffer_flush PROTO((void *));
-static int stdio_buffer_shutdown PROTO((struct buffer *buf));
-
-
-
-/* Initialize a buffer built on a stdio FILE. */
-struct stdio_buffer_closure
-{
- FILE *fp;
- int child_pid;
-};
-
-
-
-struct buffer *
-stdio_buffer_initialize (fp, child_pid, input, memory)
- FILE *fp;
- int child_pid;
- int input;
- void (*memory) PROTO((struct buffer *));
-{
- struct stdio_buffer_closure *bc = xmalloc (sizeof (*bc));
-
- bc->fp = fp;
- bc->child_pid = child_pid;
-
- return buf_initialize (input ? stdio_buffer_input : NULL,
- input ? NULL : stdio_buffer_output,
- input ? NULL : stdio_buffer_flush,
- (int (*) PROTO((void *, int))) NULL,
- stdio_buffer_shutdown,
- memory,
- (void *) bc);
-}
-
-/* Return the file associated with a stdio buffer. */
-FILE *
-stdio_buffer_get_file (buf)
- struct buffer *buf;
-{
- struct stdio_buffer_closure *bc;
-
- assert(buf->shutdown == stdio_buffer_shutdown);
-
- bc = (struct stdio_buffer_closure *) buf->closure;
-
- return(bc->fp);
-}
-
-/* The buffer input function for a buffer built on a stdio FILE. */
-
-static int
-stdio_buffer_input (closure, data, need, size, got)
- void *closure;
- char *data;
- int need;
- int size;
- int *got;
-{
- struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure;
- int nbytes;
-
- /* Since stdio does its own buffering, we don't worry about
- getting more bytes than we need. */
-
- if (need == 0 || need == 1)
- {
- int ch;
-
- ch = getc (bc->fp);
-
- if (ch == EOF)
- {
- if (feof (bc->fp))
- return -1;
- else if (errno == 0)
- return EIO;
- else
- return errno;
- }
-
- *data = ch;
- *got = 1;
- return 0;
- }
-
- nbytes = fread (data, 1, need, bc->fp);
-
- if (nbytes == 0)
- {
- *got = 0;
- if (feof (bc->fp))
- return -1;
- else if (errno == 0)
- return EIO;
- else
- return errno;
- }
-
- *got = nbytes;
-
- return 0;
-}
-
-/* The buffer output function for a buffer built on a stdio FILE. */
-
-static int
-stdio_buffer_output (closure, data, have, wrote)
- void *closure;
- const char *data;
- int have;
- int *wrote;
-{
- struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure;
-
- *wrote = 0;
-
- while (have > 0)
- {
- int nbytes;
-
- nbytes = fwrite (data, 1, have, bc->fp);
-
- if (nbytes != have)
- {
- if (errno == 0)
- return EIO;
- else
- return errno;
- }
-
- *wrote += nbytes;
- have -= nbytes;
- data += nbytes;
- }
-
- return 0;
-}
-
-
-
-/* The buffer flush function for a buffer built on a stdio FILE. */
-static int
-stdio_buffer_flush (closure)
- void *closure;
-{
- struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure;
-
- if (fflush (bc->fp) != 0)
- {
- if (errno == 0)
- return EIO;
- else
- return errno;
- }
-
- return 0;
-}
-
-
-
-static int
-stdio_buffer_shutdown (buf)
- struct buffer *buf;
-{
- struct stdio_buffer_closure *bc = buf->closure;
- struct stat s;
- int closefp, statted;
-
- /* Must be a pipe or a socket. What could go wrong?
- * Well, apparently for disconnected clients under AIX, the
- * fstat() will return -1 on the server if the client has gone
- * away.
- */
- if (fstat(fileno(bc->fp), &s) == -1) statted = 0;
- else statted = 1;
- closefp = statted;
-
- /* Flush the buffer if we can */
- if (buf->flush)
- {
- buf_flush (buf, 1);
- buf->flush = NULL;
- }
-
- if (buf->input)
- {
- /* There used to be a check here for unread data in the buffer of on
- * the pipe, but it was deemed unnecessary and possibly dangerous. In
- * some sense it could be second-guessing the caller who requested it
- * closed, as well.
- */
-
-# ifdef SHUTDOWN_SERVER
- if (current_parsed_root->method != server_method)
-# endif
-# ifndef NO_SOCKET_TO_FD
- {
- /* shutdown() sockets */
- if (statted && S_ISSOCK (s.st_mode))
- shutdown (fileno (bc->fp), 0);
- }
-# endif /* NO_SOCKET_TO_FD */
-# ifdef START_RSH_WITH_POPEN_RW
- /* Can't be set with SHUTDOWN_SERVER defined */
- else if (pclose (bc->fp) == EOF)
- {
- error (0, errno, "closing connection to %s",
- current_parsed_root->hostname);
- closefp = 0;
- }
-# endif /* START_RSH_WITH_POPEN_RW */
-
- buf->input = NULL;
- }
- else if (buf->output)
- {
-# ifdef SHUTDOWN_SERVER
- /* FIXME: Should have a SHUTDOWN_SERVER_INPUT &
- * SHUTDOWN_SERVER_OUTPUT
- */
- if (current_parsed_root->method == server_method)
- SHUTDOWN_SERVER (fileno (bc->fp));
- else
-# endif
-# ifndef NO_SOCKET_TO_FD
- /* shutdown() sockets */
- if (statted && S_ISSOCK (s.st_mode))
- shutdown (fileno (bc->fp), 1);
-# else
- {
- /* I'm not sure I like this empty block, but the alternative
- * is a another nested NO_SOCKET_TO_FD switch above.
- */
- }
-# endif /* NO_SOCKET_TO_FD */
-
- buf->output = NULL;
- }
-
- if (statted && closefp && fclose (bc->fp) == EOF)
- {
- if (server_active)
- {
- /* Syslog this? */
- }
-# ifdef CLIENT_SUPPORT
- /* We are already closing the connection.
- * On error, print a warning and try to
- * continue to avoid infinte loops.
- */
- else
- error (0, errno,
- "closing down connection to %s",
- current_parsed_root->hostname);
-# endif /* CLIENT_SUPPORT */
- }
-
- /* If we were talking to a process, make sure it exited */
- if (bc->child_pid)
- {
- int w;
-
- do
- w = waitpid (bc->child_pid, (int *) 0, 0);
- while (w == -1 && errno == EINTR);
-
- /* We are already closing the connection.
- * On error, print a warning and try to
- * continue to avoid infinte loops.
- */
- if (w == -1)
- error (0, errno, "waiting for process %d", bc->child_pid);
- }
- return 0;
-}
-
-
-
-/* Certain types of communication input and output data in packets,
- where each packet is translated in some fashion. The packetizing
- buffer type supports that, given a buffer which handles lower level
- I/O and a routine to translate the data in a packet.
-
- This code uses two bytes for the size of a packet, so packets are
- restricted to 65536 bytes in total.
-
- The translation functions should just translate; they may not
- significantly increase or decrease the amount of data. The actual
- size of the initial data is part of the translated data. The
- output translation routine may add up to PACKET_SLOP additional
- bytes, and the input translation routine should shrink the data
- correspondingly. */
-
-#define PACKET_SLOP (100)
-
-/* This structure is the closure field of a packetizing buffer. */
-
-struct packetizing_buffer
-{
- /* The underlying buffer. */
- struct buffer *buf;
- /* The input translation function. Exactly one of inpfn and outfn
- will be NULL. The input translation function should
- untranslate the data in INPUT, storing the result in OUTPUT.
- SIZE is the amount of data in INPUT, and is also the size of
- OUTPUT. This should return 0 on success, or an errno code. */
- int (*inpfn) PROTO((void *fnclosure, const char *input, char *output,
- int size));
- /* The output translation function. This should translate the
- data in INPUT, storing the result in OUTPUT. The first two
- bytes in INPUT will be the size of the data, and so will SIZE.
- This should set *TRANSLATED to the amount of translated data in
- OUTPUT. OUTPUT is large enough to hold SIZE + PACKET_SLOP
- bytes. This should return 0 on success, or an errno code. */
- int (*outfn) PROTO((void *fnclosure, const char *input, char *output,
- int size, int *translated));
- /* A closure for the translation function. */
- void *fnclosure;
- /* For an input buffer, we may have to buffer up data here. */
- /* This is non-zero if the buffered data has been translated.
- Otherwise, the buffered data has not been translated, and starts
- with the two byte packet size. */
- int translated;
- /* The amount of buffered data. */
- int holdsize;
- /* The buffer allocated to hold the data. */
- char *holdbuf;
- /* The size of holdbuf. */
- int holdbufsize;
- /* If translated is set, we need another data pointer to track
- where we are in holdbuf. If translated is clear, then this
- pointer is not used. */
- char *holddata;
-};
-
-static int packetizing_buffer_input PROTO((void *, char *, int, int, int *));
-static int packetizing_buffer_output PROTO((void *, const char *, int, int *));
-static int packetizing_buffer_flush PROTO((void *));
-static int packetizing_buffer_block PROTO((void *, int));
-static int packetizing_buffer_shutdown PROTO((struct buffer *));
-
-/* Create a packetizing buffer. */
-
-struct buffer *
-packetizing_buffer_initialize (buf, inpfn, outfn, fnclosure, memory)
- struct buffer *buf;
- int (*inpfn) PROTO ((void *, const char *, char *, int));
- int (*outfn) PROTO ((void *, const char *, char *, int, int *));
- void *fnclosure;
- void (*memory) PROTO((struct buffer *));
-{
- struct packetizing_buffer *pb;
-
- pb = (struct packetizing_buffer *) xmalloc (sizeof *pb);
- memset (pb, 0, sizeof *pb);
-
- pb->buf = buf;
- pb->inpfn = inpfn;
- pb->outfn = outfn;
- pb->fnclosure = fnclosure;
-
- if (inpfn != NULL)
- {
- /* Add PACKET_SLOP to handle larger translated packets, and
- add 2 for the count. This buffer is increased if
- necessary. */
- pb->holdbufsize = BUFFER_DATA_SIZE + PACKET_SLOP + 2;
- pb->holdbuf = xmalloc (pb->holdbufsize);
- }
-
- return buf_initialize (inpfn != NULL ? packetizing_buffer_input : NULL,
- inpfn != NULL ? NULL : packetizing_buffer_output,
- inpfn != NULL ? NULL : packetizing_buffer_flush,
- packetizing_buffer_block,
- packetizing_buffer_shutdown,
- memory,
- pb);
-}
-
-/* Input data from a packetizing buffer. */
-
-static int
-packetizing_buffer_input (closure, data, need, size, got)
- void *closure;
- char *data;
- int need;
- int size;
- int *got;
-{
- struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
-
- *got = 0;
-
- if (pb->holdsize > 0 && pb->translated)
- {
- int copy;
-
- copy = pb->holdsize;
-
- if (copy > size)
- {
- memcpy (data, pb->holddata, size);
- pb->holdsize -= size;
- pb->holddata += size;
- *got = size;
- return 0;
- }
-
- memcpy (data, pb->holddata, copy);
- pb->holdsize = 0;
- pb->translated = 0;
-
- data += copy;
- need -= copy;
- size -= copy;
- *got = copy;
- }
-
- while (need > 0 || *got == 0)
- {
- int get, status, nread, count, tcount;
- char *bytes;
- char stackoutbuf[BUFFER_DATA_SIZE + PACKET_SLOP];
- char *inbuf, *outbuf;
-
- /* If we don't already have the two byte count, get it. */
- if (pb->holdsize < 2)
- {
- get = 2 - pb->holdsize;
- status = buf_read_data (pb->buf, get, &bytes, &nread);
- if (status != 0)
- {
- /* buf_read_data can return -2, but a buffer input
- function is only supposed to return -1, 0, or an
- error code. */
- if (status == -2)
- status = ENOMEM;
- return status;
- }
-
- if (nread == 0)
- {
- /* The buffer is in nonblocking mode, and we didn't
- manage to read anything. */
- return 0;
- }
-
- if (get == 1)
- pb->holdbuf[1] = bytes[0];
- else
- {
- pb->holdbuf[0] = bytes[0];
- if (nread < 2)
- {
- /* We only got one byte, but we needed two. Stash
- the byte we got, and try again. */
- pb->holdsize = 1;
- continue;
- }
- pb->holdbuf[1] = bytes[1];
- }
- pb->holdsize = 2;
- }
-
- /* Read the packet. */
-
- count = (((pb->holdbuf[0] & 0xff) << 8)
- + (pb->holdbuf[1] & 0xff));
-
- if (count + 2 > pb->holdbufsize)
- {
- char *n;
-
- /* We didn't allocate enough space in the initialize
- function. */
-
- n = xrealloc (pb->holdbuf, count + 2);
- if (n == NULL)
- {
- (*pb->buf->memory_error) (pb->buf);
- return ENOMEM;
- }
- pb->holdbuf = n;
- pb->holdbufsize = count + 2;
- }
-
- get = count - (pb->holdsize - 2);
-
- status = buf_read_data (pb->buf, get, &bytes, &nread);
- if (status != 0)
- {
- /* buf_read_data can return -2, but a buffer input
- function is only supposed to return -1, 0, or an error
- code. */
- if (status == -2)
- status = ENOMEM;
- return status;
- }
-
- if (nread == 0)
- {
- /* We did not get any data. Presumably the buffer is in
- nonblocking mode. */
- return 0;
- }
-
- if (nread < get)
- {
- /* We did not get all the data we need to fill the packet.
- buf_read_data does not promise to return all the bytes
- requested, so we must try again. */
- memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
- pb->holdsize += nread;
- continue;
- }
-
- /* We have a complete untranslated packet of COUNT bytes. */
-
- if (pb->holdsize == 2)
- {
- /* We just read the entire packet (the 2 bytes in
- PB->HOLDBUF are the size). Save a memcpy by
- translating directly from BYTES. */
- inbuf = bytes;
- }
- else
- {
- /* We already had a partial packet in PB->HOLDBUF. We
- need to copy the new data over to make the input
- contiguous. */
- memcpy (pb->holdbuf + pb->holdsize, bytes, nread);
- inbuf = pb->holdbuf + 2;
- }
-
- if (count <= sizeof stackoutbuf)
- outbuf = stackoutbuf;
- else
- {
- outbuf = xmalloc (count);
- if (outbuf == NULL)
- {
- (*pb->buf->memory_error) (pb->buf);
- return ENOMEM;
- }
- }
-
- status = (*pb->inpfn) (pb->fnclosure, inbuf, outbuf, count);
- if (status != 0)
- return status;
-
- /* The first two bytes in the translated buffer are the real
- length of the translated data. */
- tcount = ((outbuf[0] & 0xff) << 8) + (outbuf[1] & 0xff);
-
- if (tcount > count)
- error (1, 0, "Input translation failure");
-
- if (tcount > size)
- {
- /* We have more data than the caller has provided space
- for. We need to save some of it for the next call. */
-
- memcpy (data, outbuf + 2, size);
- *got += size;
-
- pb->holdsize = tcount - size;
- memcpy (pb->holdbuf, outbuf + 2 + size, tcount - size);
- pb->holddata = pb->holdbuf;
- pb->translated = 1;
-
- if (outbuf != stackoutbuf)
- free (outbuf);
-
- return 0;
- }
-
- memcpy (data, outbuf + 2, tcount);
-
- if (outbuf != stackoutbuf)
- free (outbuf);
-
- pb->holdsize = 0;
-
- data += tcount;
- need -= tcount;
- size -= tcount;
- *got += tcount;
- }
-
- return 0;
-}
-
-/* Output data to a packetizing buffer. */
-
-static int
-packetizing_buffer_output (closure, data, have, wrote)
- void *closure;
- const char *data;
- int have;
- int *wrote;
-{
- struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
- char inbuf[BUFFER_DATA_SIZE + 2];
- char stack_outbuf[BUFFER_DATA_SIZE + PACKET_SLOP + 4];
- struct buffer_data *outdata = NULL;
- char *outbuf;
- int size, status, translated;
-
- if (have > BUFFER_DATA_SIZE)
- {
- /* It would be easy to xmalloc a buffer, but I don't think this
- case can ever arise. */
- abort ();
- }
-
- inbuf[0] = (have >> 8) & 0xff;
- inbuf[1] = have & 0xff;
- memcpy (inbuf + 2, data, have);
-
- size = have + 2;
-
- /* The output function is permitted to add up to PACKET_SLOP
- bytes, and we need 2 bytes for the size of the translated data.
- If we can guarantee that the result will fit in a buffer_data,
- we translate directly into one to avoid a memcpy in buf_output. */
- if (size + PACKET_SLOP + 2 > BUFFER_DATA_SIZE)
- outbuf = stack_outbuf;
- else
- {
- outdata = get_buffer_data ();
- if (outdata == NULL)
- {
- (*pb->buf->memory_error) (pb->buf);
- return ENOMEM;
- }
-
- outdata->next = NULL;
- outdata->bufp = outdata->text;
-
- outbuf = outdata->text;
- }
-
- status = (*pb->outfn) (pb->fnclosure, inbuf, outbuf + 2, size,
- &translated);
- if (status != 0)
- return status;
-
- /* The output function is permitted to add up to PACKET_SLOP
- bytes. */
- if (translated > size + PACKET_SLOP)
- abort ();
-
- outbuf[0] = (translated >> 8) & 0xff;
- outbuf[1] = translated & 0xff;
-
- if (outbuf == stack_outbuf)
- buf_output (pb->buf, outbuf, translated + 2);
- else
- {
- /* if ((have + PACKET_SLOP + 4) > BUFFER_DATA_SIZE), then
- outdata may be NULL. */
- if (outdata == NULL)
- abort ();
-
- outdata->size = translated + 2;
- buf_append_data (pb->buf, outdata, outdata);
- }
-
- *wrote = have;
-
- /* We will only be here because buf_send_output was called on the
- packetizing buffer. That means that we should now call
- buf_send_output on the underlying buffer. */
- return buf_send_output (pb->buf);
-}
-
-
-
-/* Flush data to a packetizing buffer. */
-static int
-packetizing_buffer_flush (closure)
- void *closure;
-{
- struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
-
- /* Flush the underlying buffer. Note that if the original call to
- buf_flush passed 1 for the BLOCK argument, then the buffer will
- already have been set into blocking mode, so we should always
- pass 0 here. */
- return buf_flush (pb->buf, 0);
-}
-
-
-
-/* The block routine for a packetizing buffer. */
-static int
-packetizing_buffer_block (closure, block)
- void *closure;
- int block;
-{
- struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
-
- if (block)
- return set_block (pb->buf);
- else
- return set_nonblock (pb->buf);
-}
-
-/* Shut down a packetizing buffer. */
-
-static int
-packetizing_buffer_shutdown (buf)
- struct buffer *buf;
-{
- struct packetizing_buffer *pb = (struct packetizing_buffer *) buf->closure;
-
- return buf_shutdown (pb->buf);
-}
-
-#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
OpenPOWER on IntegriCloud