1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 8 #include "config.h" 9 10 #ifndef lint 11 static const char sccsid[] = "@(#)db_ret.c 10.16 (Sleepycat) 10/4/98"; 12 #endif /* not lint */ 13 14 #ifndef NO_SYSTEM_INCLUDES 15 #include <sys/types.h> 16 17 #include <errno.h> 18 #include <string.h> 19 #endif 20 21 #include "db_int.h" 22 #include "db_page.h" 23 #include "btree.h" 24 #include "db_am.h" 25 26 /* 27 * __db_ret -- 28 * Build return DBT. 29 * 30 * PUBLIC: int __db_ret __P((DB *, 31 * PUBLIC: PAGE *, u_int32_t, DBT *, void **, u_int32_t *)); 32 */ 33 int 34 __db_ret(dbp, h, indx, dbt, memp, memsize) 35 DB *dbp; 36 PAGE *h; 37 u_int32_t indx; 38 DBT *dbt; 39 void **memp; 40 u_int32_t *memsize; 41 { 42 BKEYDATA *bk; 43 HOFFPAGE ho; 44 BOVERFLOW *bo; 45 u_int32_t len; 46 u_int8_t *hk; 47 void *data; 48 49 switch (TYPE(h)) { 50 case P_HASH: 51 hk = P_ENTRY(h, indx); 52 if (HPAGE_PTYPE(hk) == H_OFFPAGE) { 53 memcpy(&ho, hk, sizeof(HOFFPAGE)); 54 return (__db_goff(dbp, dbt, 55 ho.tlen, ho.pgno, memp, memsize)); 56 } 57 len = LEN_HKEYDATA(h, dbp->pgsize, indx); 58 data = HKEYDATA_DATA(hk); 59 break; 60 case P_DUPLICATE: 61 case P_LBTREE: 62 case P_LRECNO: 63 bk = GET_BKEYDATA(h, indx); 64 if (B_TYPE(bk->type) == B_OVERFLOW) { 65 bo = (BOVERFLOW *)bk; 66 return (__db_goff(dbp, dbt, 67 bo->tlen, bo->pgno, memp, memsize)); 68 } 69 len = bk->len; 70 data = bk->data; 71 break; 72 default: 73 return (__db_pgfmt(dbp, h->pgno)); 74 } 75 76 return (__db_retcopy(dbt, data, len, memp, memsize, 77 F_ISSET(dbt, DB_DBT_INTERNAL) ? NULL : dbp->db_malloc)); 78 } 79 80 /* 81 * __db_retcopy -- 82 * Copy the returned data into the user's DBT, handling special flags. 83 * 84 * PUBLIC: int __db_retcopy __P((DBT *, 85 * PUBLIC: void *, u_int32_t, void **, u_int32_t *, void *(*)(size_t))); 86 */ 87 int 88 __db_retcopy(dbt, data, len, memp, memsize, db_malloc) 89 DBT *dbt; 90 void *data; 91 u_int32_t len; 92 void **memp; 93 u_int32_t *memsize; 94 void *(*db_malloc) __P((size_t)); 95 { 96 int ret; 97 98 /* If returning a partial record, reset the length. */ 99 if (F_ISSET(dbt, DB_DBT_PARTIAL)) { 100 data = (u_int8_t *)data + dbt->doff; 101 if (len > dbt->doff) { 102 len -= dbt->doff; 103 if (len > dbt->dlen) 104 len = dbt->dlen; 105 } else 106 len = 0; 107 } 108 109 /* 110 * Return the length of the returned record in the DBT size field. 111 * This satisfies the requirement that if we're using user memory 112 * and insufficient memory was provided, return the amount necessary 113 * in the size field. 114 */ 115 dbt->size = len; 116 117 /* 118 * Allocate memory to be owned by the application: DB_DBT_MALLOC. 119 * 120 * !!! 121 * We always allocate memory, even if we're copying out 0 bytes. This 122 * guarantees consistency, i.e., the application can always free memory 123 * without concern as to how many bytes of the record were requested. 124 * 125 * Use the memory specified by the application: DB_DBT_USERMEM. 126 * 127 * !!! 128 * If the length we're going to copy is 0, the application-supplied 129 * memory pointer is allowed to be NULL. 130 */ 131 if (F_ISSET(dbt, DB_DBT_MALLOC)) { 132 if ((ret = __os_malloc(len, db_malloc, &dbt->data)) != 0) 133 return (ret); 134 } else if (F_ISSET(dbt, DB_DBT_USERMEM)) { 135 if (len != 0 && (dbt->data == NULL || dbt->ulen < len)) 136 return (ENOMEM); 137 } else if (memp == NULL || memsize == NULL) { 138 return (EINVAL); 139 } else { 140 if (len != 0 && (*memsize == 0 || *memsize < len)) { 141 if ((ret = __os_realloc(memp, len)) != 0) { 142 *memsize = 0; 143 return (ret); 144 } 145 *memsize = len; 146 } 147 dbt->data = *memp; 148 } 149 150 if (len != 0) 151 memcpy(dbt->data, data, len); 152 return (0); 153 } 154