1169689Skan/*	$NetBSD: rec_get.c,v 1.15 2008/09/10 17:52:36 joerg Exp $	*/
2169689Skan
3169689Skan/*-
4169689Skan * Copyright (c) 1990, 1993, 1994
5169689Skan *	The Regents of the University of California.  All rights reserved.
6169689Skan *
7169689Skan * Redistribution and use in source and binary forms, with or without
8169689Skan * modification, are permitted provided that the following conditions
9169689Skan * are met:
10169689Skan * 1. Redistributions of source code must retain the above copyright
11169689Skan *    notice, this list of conditions and the following disclaimer.
12169689Skan * 2. Redistributions in binary form must reproduce the above copyright
13169689Skan *    notice, this list of conditions and the following disclaimer in the
14169689Skan *    documentation and/or other materials provided with the distribution.
15169689Skan * 3. Neither the name of the University nor the names of its contributors
16169689Skan *    may be used to endorse or promote products derived from this software
17169689Skan *    without specific prior written permission.
18169689Skan *
19169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29169689Skan * SUCH DAMAGE.
30169689Skan */
31169689Skan
32169689Skan#if HAVE_NBTOOL_CONFIG_H
33169689Skan#include "nbtool_config.h"
34169689Skan#endif
35169689Skan
36169689Skan#include <sys/cdefs.h>
37169689Skan__RCSID("$NetBSD: rec_get.c,v 1.15 2008/09/10 17:52:36 joerg Exp $");
38169689Skan
39169689Skan#include "namespace.h"
40169689Skan#include <sys/types.h>
41169689Skan
42169689Skan#include <assert.h>
43169689Skan#include <errno.h>
44169689Skan#include <stddef.h>
45169689Skan#include <stdio.h>
46169689Skan#include <stdlib.h>
47169689Skan#include <string.h>
48169689Skan#include <unistd.h>
49169689Skan
50169689Skan#include <db.h>
51169689Skan#include "recno.h"
52169689Skan
53169689Skan/*
54169689Skan * __REC_GET -- Get a record from the btree.
55169689Skan *
56169689Skan * Parameters:
57169689Skan *	dbp:	pointer to access method
58169689Skan *	key:	key to find
59169689Skan *	data:	data to return
60169689Skan *	flag:	currently unused
61169689Skan *
62169689Skan * Returns:
63169689Skan *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
64169689Skan */
65169689Skanint
66169689Skan__rec_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
67169689Skan{
68169689Skan	BTREE *t;
69169689Skan	EPG *e;
70169689Skan	recno_t nrec;
71169689Skan	int status;
72169689Skan
73169689Skan	t = dbp->internal;
74169689Skan
75169689Skan	/* Toss any page pinned across calls. */
76169689Skan	if (t->bt_pinned != NULL) {
77169689Skan		mpool_put(t->bt_mp, t->bt_pinned, 0);
78169689Skan		t->bt_pinned = NULL;
79169689Skan	}
80169689Skan
81169689Skan	/* Get currently doesn't take any flags, and keys of 0 are illegal. */
82169689Skan	if (flags || (nrec = *(recno_t *)key->data) == 0) {
83169689Skan		errno = EINVAL;
84169689Skan		return (RET_ERROR);
85169689Skan	}
86169689Skan
87169689Skan	/*
88169689Skan	 * If we haven't seen this record yet, try to find it in the
89169689Skan	 * original file.
90169689Skan	 */
91169689Skan	if (nrec > t->bt_nrecs) {
92169689Skan		if (F_ISSET(t, R_EOF | R_INMEM))
93169689Skan			return (RET_SPECIAL);
94169689Skan		if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
95169689Skan			return (status);
96169689Skan	}
97169689Skan
98169689Skan	--nrec;
99169689Skan	if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
100169689Skan		return (RET_ERROR);
101169689Skan
102169689Skan	status = __rec_ret(t, e, 0, NULL, data);
103169689Skan	if (F_ISSET(t, B_DB_LOCK))
104169689Skan		mpool_put(t->bt_mp, e->page, 0);
105169689Skan	else
106169689Skan		t->bt_pinned = e->page;
107169689Skan	return (status);
108169689Skan}
109169689Skan
110169689Skan/*
111169689Skan * __REC_FPIPE -- Get fixed length records from a pipe.
112169689Skan *
113169689Skan * Parameters:
114169689Skan *	t:	tree
115169689Skan *	cnt:	records to read
116169689Skan *
117169689Skan * Returns:
118169689Skan *	RET_ERROR, RET_SUCCESS
119169689Skan */
120169689Skanint
121169689Skan__rec_fpipe(BTREE *t, recno_t top)
122169689Skan{
123169689Skan	DBT data;
124169689Skan	recno_t nrec;
125169689Skan	size_t len;
126169689Skan	int ch;
127169689Skan	uint8_t *p;
128169689Skan
129169689Skan	if (t->bt_rdata.size < t->bt_reclen) {
130169689Skan		t->bt_rdata.data = t->bt_rdata.data == NULL ?
131169689Skan		    malloc(t->bt_reclen) :
132169689Skan		    realloc(t->bt_rdata.data, t->bt_reclen);
133169689Skan		if (t->bt_rdata.data == NULL)
134169689Skan			return (RET_ERROR);
135169689Skan		t->bt_rdata.size = t->bt_reclen;
136169689Skan	}
137169689Skan	data.data = t->bt_rdata.data;
138169689Skan	data.size = t->bt_reclen;
139169689Skan
140169689Skan	for (nrec = t->bt_nrecs; nrec < top;) {
141169689Skan		len = t->bt_reclen;
142169689Skan		for (p = t->bt_rdata.data;; *p++ = ch)
143169689Skan			if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
144169689Skan				if (ch != EOF)
145169689Skan					*p = ch;
146169689Skan				if (len != 0)
147169689Skan					memset(p, t->bt_bval, len);
148169689Skan				if (__rec_iput(t,
149169689Skan				    nrec, &data, 0) != RET_SUCCESS)
150169689Skan					return (RET_ERROR);
151169689Skan				++nrec;
152169689Skan				break;
153169689Skan			}
154169689Skan		if (ch == EOF)
155169689Skan			break;
156169689Skan	}
157169689Skan	if (nrec < top) {
158169689Skan		F_SET(t, R_EOF);
159169689Skan		return (RET_SPECIAL);
160169689Skan	}
161169689Skan	return (RET_SUCCESS);
162169689Skan}
163169689Skan
164169689Skan/*
165169689Skan * __REC_VPIPE -- Get variable length records from a pipe.
166169689Skan *
167169689Skan * Parameters:
168169689Skan *	t:	tree
169169689Skan *	cnt:	records to read
170169689Skan *
171169689Skan * Returns:
172169689Skan *	RET_ERROR, RET_SUCCESS
173169689Skan */
174169689Skanint
175169689Skan__rec_vpipe(BTREE *t, recno_t top)
176169689Skan{
177169689Skan	DBT data;
178169689Skan	recno_t nrec;
179169689Skan	ptrdiff_t len;
180169689Skan	size_t sz;
181169689Skan	int bval, ch;
182169689Skan	uint8_t *p;
183169689Skan
184169689Skan	bval = t->bt_bval;
185169689Skan	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
186169689Skan		for (p = t->bt_rdata.data,
187169689Skan		    sz = t->bt_rdata.size;; *p++ = ch, --sz) {
188169689Skan			if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
189169689Skan				data.data = t->bt_rdata.data;
190169689Skan				data.size = p - (uint8_t *)t->bt_rdata.data;
191169689Skan				if (ch == EOF && data.size == 0)
192169689Skan					break;
193169689Skan				if (__rec_iput(t, nrec, &data, 0)
194169689Skan				    != RET_SUCCESS)
195169689Skan					return (RET_ERROR);
196169689Skan				break;
197169689Skan			}
198169689Skan			if (sz == 0) {
199169689Skan				len = p - (uint8_t *)t->bt_rdata.data;
200169689Skan				t->bt_rdata.size += (sz = 256);
201169689Skan				t->bt_rdata.data = t->bt_rdata.data == NULL ?
202169689Skan				    malloc(t->bt_rdata.size) :
203169689Skan				    realloc(t->bt_rdata.data, t->bt_rdata.size);
204169689Skan				if (t->bt_rdata.data == NULL)
205169689Skan					return (RET_ERROR);
206169689Skan				p = (uint8_t *)t->bt_rdata.data + len;
207169689Skan			}
208169689Skan		}
209169689Skan		if (ch == EOF)
210169689Skan			break;
211169689Skan	}
212169689Skan	if (nrec < top) {
213169689Skan		F_SET(t, R_EOF);
214169689Skan		return (RET_SPECIAL);
215169689Skan	}
216169689Skan	return (RET_SUCCESS);
217169689Skan}
218169689Skan
219169689Skan/*
220169689Skan * __REC_FMAP -- Get fixed length records from a file.
221169689Skan *
222169689Skan * Parameters:
223169689Skan *	t:	tree
224169689Skan *	cnt:	records to read
225169689Skan *
226169689Skan * Returns:
227169689Skan *	RET_ERROR, RET_SUCCESS
228169689Skan */
229169689Skanint
230169689Skan__rec_fmap(BTREE *t, recno_t top)
231169689Skan{
232169689Skan	DBT data;
233169689Skan	recno_t nrec;
234169689Skan	uint8_t *sp, *ep, *p;
235169689Skan	size_t len;
236169689Skan
237169689Skan	if (t->bt_rdata.size < t->bt_reclen) {
238169689Skan		t->bt_rdata.data = t->bt_rdata.data == NULL ?
239169689Skan		    malloc(t->bt_reclen) :
240169689Skan		    realloc(t->bt_rdata.data, t->bt_reclen);
241169689Skan		if (t->bt_rdata.data == NULL)
242169689Skan			return (RET_ERROR);
243169689Skan		t->bt_rdata.size = t->bt_reclen;
244169689Skan	}
245169689Skan	data.data = t->bt_rdata.data;
246169689Skan	data.size = t->bt_reclen;
247169689Skan
248169689Skan	sp = (uint8_t *)t->bt_cmap;
249169689Skan	ep = (uint8_t *)t->bt_emap;
250169689Skan	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
251169689Skan		if (sp >= ep) {
252169689Skan			F_SET(t, R_EOF);
253169689Skan			return (RET_SPECIAL);
254169689Skan		}
255169689Skan		len = t->bt_reclen;
256169689Skan		for (p = t->bt_rdata.data;
257169689Skan		    sp < ep && len > 0; *p++ = *sp++, --len);
258169689Skan		if (len != 0)
259169689Skan			memset(p, t->bt_bval, len);
260169689Skan		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
261169689Skan			return (RET_ERROR);
262169689Skan	}
263169689Skan	t->bt_cmap = (caddr_t)sp;
264169689Skan	return (RET_SUCCESS);
265169689Skan}
266169689Skan
267169689Skan/*
268169689Skan * __REC_VMAP -- Get variable length records from a file.
269169689Skan *
270169689Skan * Parameters:
271169689Skan *	t:	tree
272169689Skan *	cnt:	records to read
273169689Skan *
274169689Skan * Returns:
275169689Skan *	RET_ERROR, RET_SUCCESS
276169689Skan */
277169689Skanint
278169689Skan__rec_vmap(BTREE *t, recno_t top)
279169689Skan{
280169689Skan	DBT data;
281169689Skan	uint8_t *sp, *ep;
282169689Skan	recno_t nrec;
283169689Skan	int bval;
284169689Skan
285169689Skan	sp = (uint8_t *)t->bt_cmap;
286169689Skan	ep = (uint8_t *)t->bt_emap;
287169689Skan	bval = t->bt_bval;
288169689Skan
289169689Skan	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
290169689Skan		if (sp >= ep) {
291169689Skan			F_SET(t, R_EOF);
292169689Skan			return (RET_SPECIAL);
293169689Skan		}
294169689Skan		for (data.data = sp; sp < ep && *sp != bval; ++sp);
295169689Skan		data.size = sp - (uint8_t *)data.data;
296169689Skan		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
297169689Skan			return (RET_ERROR);
298169689Skan		++sp;
299169689Skan	}
300169689Skan	t->bt_cmap = (caddr_t)sp;
301169689Skan	return (RET_SUCCESS);
302169689Skan}
303169689Skan