summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2009-12-13 19:30:33 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2009-12-13 19:30:33 +0000
commitb5c871dff0fbf5048fa94a8a3f32d3637a1866fa (patch)
treea6a7e846bc0aecadba0b592d4c2f71aff7b22248 /gnu/usr.bin/cvs
parent46567e65e3868bec5e2a03f1d3d044137d7c6671 (diff)
fix leaks found by parfait.
ok deraadt
Diffstat (limited to 'gnu/usr.bin/cvs')
-rw-r--r--gnu/usr.bin/cvs/src/buffer.c496
-rw-r--r--gnu/usr.bin/cvs/src/server.c11
2 files changed, 499 insertions, 8 deletions
diff --git a/gnu/usr.bin/cvs/src/buffer.c b/gnu/usr.bin/cvs/src/buffer.c
index 8baa021fbb9..85178856008 100644
--- a/gnu/usr.bin/cvs/src/buffer.c
+++ b/gnu/usr.bin/cvs/src/buffer.c
@@ -16,6 +16,7 @@
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));
@@ -42,11 +43,25 @@ buf_initialize (input, output, flush, block, shutdown, memory, closure)
buf->flush = flush;
buf->block = block;
buf->shutdown = shutdown;
- buf->memory_error = memory;
+ 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->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 *
@@ -63,6 +78,15 @@ buf_nonio_initialize (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
@@ -77,9 +101,13 @@ allocate_buffer_datas ()
alc = ((struct buffer_data *)
malloc (ALLOC_COUNT * sizeof (struct buffer_data)));
- space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
- if (alc == NULL || space == NULL)
+ if (alc == NULL)
return;
+ space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE);
+ if (space == NULL) {
+ free(alc);
+ return;
+ }
for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE)
{
alc->next = free_buffer_data;
@@ -470,6 +498,19 @@ buf_append_data (buf, data, 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
@@ -621,6 +662,15 @@ buf_chain_length (buf)
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
@@ -717,7 +767,7 @@ buf_read_line (buf, line, lenp)
while (1)
{
- int len, finallen;
+ int len, finallen = 0;
struct buffer_data *data;
char *nl;
@@ -1167,8 +1217,8 @@ static int stdio_buffer_flush PROTO((void *));
/* Initialize a buffer built on a stdio FILE. */
-struct buffer
-*stdio_buffer_initialize (fp, input, memory)
+struct buffer *
+stdio_buffer_initialize (fp, input, memory)
FILE *fp;
int input;
void (*memory) PROTO((struct buffer *));
@@ -1291,4 +1341,438 @@ stdio_buffer_flush (closure)
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((void *));
+
+/* 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 = realloc (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 = malloc (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;
+ char *outbuf;
+ int size, status, translated;
+
+ if (have > BUFFER_DATA_SIZE)
+ {
+ /* It would be easy to malloc 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
+ {
+ 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 (closure)
+ void *closure;
+{
+ struct packetizing_buffer *pb = (struct packetizing_buffer *) closure;
+
+ return buf_shutdown (pb->buf);
+}
+
#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/gnu/usr.bin/cvs/src/server.c b/gnu/usr.bin/cvs/src/server.c
index 694dfb056e1..78f7a3852c2 100644
--- a/gnu/usr.bin/cvs/src/server.c
+++ b/gnu/usr.bin/cvs/src/server.c
@@ -355,14 +355,19 @@ create_adm_p (base_dir, dir)
return ENOMEM;
dir_where_cvsadm_lives = malloc (strlen (base_dir) + strlen (dir) + 100);
- if (dir_where_cvsadm_lives == NULL)
+ if (dir_where_cvsadm_lives == NULL) {
+ free(p);
return ENOMEM;
+ }
/* Allocate some space for the temporary string in which we will
construct filenames. */
tmp = malloc (strlen (base_dir) + strlen (dir) + 100);
- if (tmp == NULL)
+ if (tmp == NULL) {
+ free(p);
+ free(dir_where_cvsadm_lives);
return ENOMEM;
+ }
/* We make several passes through this loop. On the first pass,
@@ -1397,6 +1402,8 @@ receive_file (size, file, gzipped)
pending_error = status;
}
}
+ if (filebuf != NULL)
+ free(filebuf);
return;
}