summaryrefslogtreecommitdiff
path: root/dbm/src/h_bigkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbm/src/h_bigkey.c')
-rw-r--r--dbm/src/h_bigkey.c116
1 files changed, 42 insertions, 74 deletions
diff --git a/dbm/src/h_bigkey.c b/dbm/src/h_bigkey.c
index 51a5079b0..53a1a00f3 100644
--- a/dbm/src/h_bigkey.c
+++ b/dbm/src/h_bigkey.c
@@ -364,7 +364,6 @@ __big_return(
BUFHEAD *save_p;
uint16 *bp, len, off, save_addr;
char *tp;
- char save_flags;
bp = (uint16 *)bufp->page;
while (bp[ndx + 1] == PARTIAL_KEY) {
@@ -429,12 +428,7 @@ __big_return(
return (0);
}
- /* pin our saved buf so that we don't lose if
- * we run out of buffers */
- save_flags = save_p->flags;
- save_p->flags |= BUF_PIN;
val->size = collect_data(hashp, bufp, (int)len, set_current);
- save_p->flags = save_flags;
if (val->size == (size_t)-1)
return (-1);
if (save_p->addr != save_addr) {
@@ -446,14 +440,9 @@ __big_return(
val->data = (uint8 *)hashp->tmp_buf;
return (0);
}
-
-
/*
- * Count how big the total datasize is by looping through the pages. Then
- * allocate a buffer and copy the data in the second loop. NOTE: Our caller
- * may already have a bp which it is holding onto. The caller is
- * responsible for copying that bp into our temp buffer. 'len' is how much
- * space to reserve for that buffer.
+ * Count how big the total datasize is by recursing through the pages. Then
+ * allocate a buffer and copy the data as you recurse up.
*/
static int
collect_data(
@@ -462,77 +451,56 @@ collect_data(
int len, int set)
{
register uint16 *bp;
- BUFHEAD *save_bufp;
- char save_flags;
+ register char *p;
+ BUFHEAD *xbp;
+ uint16 save_addr;
int mylen, totlen;
- /*
- * save the input buf head because we need to walk the list twice.
- * pin it to make sure it doesn't leave the buffer pool.
- * This has the effect of growing the buffer pool if necessary.
- */
- save_bufp = bufp;
- save_flags = save_bufp->flags;
- save_bufp->flags |= BUF_PIN;
-
- /* read the length of the buffer */
- for (totlen = len; bufp ; bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) {
- bp = (uint16 *)bufp->page;
- mylen = hashp->BSIZE - bp[1];
- if (mylen < 0) {
- save_bufp->flags = save_flags;
- return (-1);
- }
- totlen += mylen;
- if (bp[2] == FULL_KEY_DATA) {
- break;
- }
- }
-
- if (!bufp) {
- save_bufp->flags = save_flags;
- return (-1);
- }
+ p = bufp->page;
+ bp = (uint16 *)p;
+ mylen = hashp->BSIZE - bp[1];
- /* allocate a temp buf */
- if (hashp->tmp_buf)
- free(hashp->tmp_buf);
- if ((hashp->tmp_buf = (char *)malloc((size_t)totlen)) == NULL) {
- save_bufp->flags = save_flags;
+ /* if mylen ever goes negative it means that the
+ * page is screwed up.
+ */
+ if(mylen < 0)
return (-1);
- }
-
- /* copy the buffers back into temp buf */
- for (bufp = save_bufp; bufp ;
- bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) {
- bp = (uint16 *)bufp->page;
- mylen = hashp->BSIZE - bp[1];
- memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], (size_t)mylen);
- len += mylen;
- if (bp[2] == FULL_KEY_DATA) {
- break;
- }
- }
- /* 'clear' the pin flags */
- save_bufp->flags = save_flags;
+ save_addr = bufp->addr;
- /* update the database cursor */
- if (set) {
- hashp->cndx = 1;
- if (bp[0] == 2) { /* No more buckets in chain */
- hashp->cpage = NULL;
- hashp->cbucket++;
- } else {
- hashp->cpage = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
- if (!hashp->cpage)
- return (-1);
- else if (!((uint16 *)hashp->cpage->page)[0]) {
- hashp->cbucket++;
+ if (bp[2] == FULL_KEY_DATA) { /* End of Data */
+ totlen = len + mylen;
+ if (hashp->tmp_buf)
+ free(hashp->tmp_buf);
+ if ((hashp->tmp_buf = (char *)malloc((size_t)totlen)) == NULL)
+ return (-1);
+ if (set) {
+ hashp->cndx = 1;
+ if (bp[0] == 2) { /* No more buckets in chain */
hashp->cpage = NULL;
+ hashp->cbucket++;
+ } else {
+ hashp->cpage =
+ __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!hashp->cpage)
+ return (-1);
+ else if (!((uint16 *)hashp->cpage->page)[0]) {
+ hashp->cbucket++;
+ hashp->cpage = NULL;
+ }
}
}
+ } else {
+ xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!xbp || ((totlen =
+ collect_data(hashp, xbp, len + mylen, set)) < 1))
+ return (-1);
+ }
+ if (bufp->addr != save_addr) {
+ errno = EINVAL; /* Out of buffers. */
+ return (-1);
}
+ memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], (size_t)mylen);
return (totlen);
}