Import of pkgsrc-2013Q2

This commit is contained in:
2013-09-26 17:14:40 +02:00
commit 785076ae39
74991 changed files with 4380255 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
# $NetBSD: Makefile.in,v 1.36 2009/06/05 19:58:04 joerg Exp $
#
srcdir= @srcdir@
prefix= @prefix@
VPATH= @srcdir@
SHELL= /bin/sh
CC= @CC@
CCLD= @CC@
CFLAGS= -I$(srcdir) -I. @INCLUDES@ @CFLAGS@
CPPFLAGS= @CPPFLAGS@
DEFS= @DEFS@
INSTALL= @INSTALL@
LIBMODE?= 644
LDFLAGS= @LDFLAGS@
AWK= @AWK@
AR= @AR@
RANLIB= @RANLIB@
LIB= libnbcompat.a
INCS= nbcompat.h \
nbcompat/assert.h \
nbcompat/cdefs.h \
nbcompat/ctype.h \
nbcompat/dirent.h \
nbcompat/endian.h \
nbcompat/err.h \
nbcompat/fnmatch.h \
nbcompat/fts.h \
nbcompat/getopt.h \
nbcompat/glob.h \
nbcompat/grp.h \
nbcompat/limits.h \
nbcompat/md5.h \
nbcompat/nbconfig.h \
nbcompat/netdb.h \
nbcompat/param.h \
nbcompat/paths.h \
nbcompat/poll.h \
nbcompat/pwd.h \
nbcompat/queue.h \
nbcompat/regex.h \
nbcompat/rmd160.h \
nbcompat/sha1.h \
nbcompat/sha2.h \
nbcompat/stat.h \
nbcompat/statvfs.h \
nbcompat/stdbool.h \
nbcompat/stdio.h \
nbcompat/stdlib.h \
nbcompat/string.h \
nbcompat/termcap.h \
nbcompat/time.h \
nbcompat/types.h \
nbcompat/tzfile.h \
nbcompat/unistd.h \
nbcompat/util.h \
nbcompat/vis.h
OBJS= @LIBOBJS@
WITH_DB= @WITH_DB@
.if ${WITH_DB} == "yes"
. include "${.CURDIR}/db/Makefile.inc"
.endif
LINK= $(CCLD) $(CFLAGS) $(LDFLAGS) -o $@
COMPILE= $(CC) $(CPPFLAGS) $(CFLAGS)
all: nbcompat/nbconfig.h $(LIB)
.c.o:
$(COMPILE) $(DEFS) -c $<
$(LIB): $(OBJS)
$(AR) cr $@ $(OBJS)
$(RANLIB) $@
nbcompat/nbconfig.h: nbcompat/config.h nbcompat.awk
$(AWK) -f nbcompat.awk nbcompat/config.h > $@
install:
$(INSTALL) -m 755 -d ${DESTDIR}$(prefix)/lib
$(INSTALL) -m $(LIBMODE) ${LIB} ${DESTDIR}$(prefix)/lib
$(RANLIB) ${DESTDIR}$(prefix)/lib/$(LIB)
$(INSTALL) -m 755 -d ${DESTDIR}$(prefix)/include
$(INSTALL) -m 755 -d ${DESTDIR}$(prefix)/include/nbcompat
@for file in $(INCS); do \
echo "$(INSTALL) -m 444 $$file ${DESTDIR}$(prefix)/include/$$file"; \
$(INSTALL) -m 444 $$file ${DESTDIR}$(prefix)/include/$$file; \
done
clean:
rm -f *.a *.o bits nbcompat/nbcompat.h
distclean: clean
rm -f Makefile config.log config.status configure.lineno
rm -f nbcompat/config.h nbcompat/nbconfig.h

View File

@@ -0,0 +1,112 @@
$NetBSD: README,v 1.18 2007/07/21 14:39:25 tnn Exp $
0 Introduction
==============
libnbcompat builds and installs a portable NetBSD-compatibility library
that supplies routines missing on operating systems that are used by
the family of pkgsrc bootstrap tools. Note that libnbcompat is very
much a work-in-progress. Only the functions that are directly used
by the bootstrap tools are implemented in the library. At the moment,
this includes the following packages:
archivers/pax
pkgtools/mtree
pkgtools/pkg_install
textproc/nbsed
A script, src2nbcompat, is also included in the sources that simplifies
importing software from the NetBSD src module into pkgsrc.
1 Updating this package
=======================
Please take care when updating this package. Do *not* simply commit
changes to this package and ask for testers. This package is too
fundamental to the proper bootstrapping of pkgsrc to let accidental
breakage seep in. Proper methodology for updating this package is:
(1) Post a tarball at a publicly accessible URL containing the
pkgtools/libnbcompat directory.
(2) Ask on the tech-pkg@NetBSD.org mailing list for testers.
(3) Fix any breakage on non-NetBSD operating systems before
committing.
2 Tested operating systems
==========================
*NOTE*
*NOTE* This section should be kept up-to-date with the results for
*NOTE* the most recent libnbcompat.
*NOTE*
libnbcompat-20040911 has been tested to build and install correctly
on the following operating systems:
FreeBSD-4.8/i386 <jlam@NetBSD.org>
NetBSD-1.6.2/i386 <jlam@NetBSD.org>
Solaris 9/sparc <salo@NetBSD.org>
libnbcompat-20041024 has been tested to build and install correctly
on the following operating systems:
FreeBSD-4.11/i386 <jschauma@NetBSD.org>
FreeBSD-6.1/amd64 <jschauma@NetBSD.org>
Darwin-8.3/powerpc <schwarz@NetBSD.org>
IRIX-5.3/mipseb <schwarz@NetBSD.org>
IRIX-6.5/mipseb <jschauma@NetBSD.org>
Linux/i386 <schwarz@NetBSD.org>
RHEL4 Linux 2.6/i386 <jschauma@NetBSD.org>
libnbcompat-20070507 has been tested to build and install correctly
on the following operating systems:
DragonFly-1.8/i386 <joerg@NetBSD.org>
libnbcompat-20070531 has been tested to build and install correctly
on the following operating systems:
SunOS-5.10-sparc <rillig@NetBSD.org>
NetBSD-3.0-i386 <rillig@NetBSD.org>
IRIX-6.5-mips <rillig@NetBSD.org>
libnbcompat-20070721 has been tested to build and install correctly
on the following operating systems:
HPUX-11.11-hppa <tnn@NetBSD.org>
Interix-3.5-i586 <tnn@NetBSD.org>
3 Usage
=======
This library is intended to simplify porting NetBSD software. To that
end, the changes to NetBSD sources to use libnbcompat are minor. The
procedure is:
(1) Add #include <nbcompat.h> at the top of the source files that
include system headers, but below the inclusion of any
"config.h".
(2) Surround each system header file included in the source file
with #if HAVE_<header_name>_H ... #endif.
You may need to add additional headers present on other operating
systems that define any system-supplied functions, e.g. <sys/vfs.h>.
The src2nbcompat script included in the libncompat sources can be used
to automate this process to some extent. It is intended to import
sources from a NetBSD src checkout into pkgsrc. It will copy the
sources from a directory and automatically insert the proper lines
into the files. For example, to import the pkg_install sources into
pkgsrc, run:
src2nbcompat \
/usr/src/usr.sbin/pkg_install \
/usr/pkgsrc/pkgtools/pkg_install/files
You will need to run a "cvs diff" on the imported files to check that
any local changes are preserved across imports.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
/* $NetBSD: __unsetenv13.c,v 1.1 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "from: @(#)setenv.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: __unsetenv13.c,v 1.1 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#if 0
#include "namespace.h"
#endif
#include <nbcompat/assert.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdlib.h>
#include <nbcompat/string.h>
#if 0
#include "local.h"
#include "reentrant.h"
#endif
char *__findenv __P((const char *, int *));
#if 0
#ifdef __weak_alias
#ifdef __LIBC12_SOURCE__
__weak_alias(unsetenv,_unsetenv)
#endif
#endif
#endif
#if 0
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
#endif
#if 0
#ifdef __LIBC12_SOURCE__
__warn_references(unsetenv,
"warning: reference to compatibility unsetenv();"
" include <stdlib.h> for correct reference")
#endif
#endif
extern char **environ;
#ifndef rwlock_wrlock
#define rwlock_wrlock(lock) ((void)0)
#endif
#ifndef rwlock_unlock
#define rwlock_unlock(lock) ((void)0)
#endif
/*
* unsetenv(name) --
* Delete environmental variable "name".
*/
#ifdef __LIBC12_SOURCE__
void
#else
int
#endif
unsetenv(name)
const char *name;
{
char **p;
int offset;
_DIAGASSERT(name != NULL);
#ifndef __LIBC12_SOURCE__
if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
errno = EINVAL;
return (-1);
}
#endif
rwlock_wrlock(&__environ_lock);
while (__findenv(name, &offset)) /* if set multiple times */
for (p = &environ[offset];; ++p)
if (!(*p = *(p + 1)))
break;
rwlock_unlock(&__environ_lock);
#ifndef __LIBC12_SOURCE__
return (0);
#endif
}

143
pkgtools/libnbcompat/files/aclocal.m4 vendored Normal file
View File

@@ -0,0 +1,143 @@
dnl $NetBSD: aclocal.m4,v 1.4 2006/03/01 16:47:54 joerg Exp $
dnl
dnl
dnl AC_MSG_TRY_COMPILE
dnl
dnl Written by Luke Mewburn <lukem@netbsd.org>
dnl
dnl Usage:
dnl AC_MSG_TRY_COMPILE(Message, CacheVar, Includes, Code,
dnl ActionPass [,ActionFail] )
dnl
dnl effectively does:
dnl AC_CACHE_CHECK(Message, CacheVar,
dnl AC_TRY_COMPILE(Includes, Code, CacheVar = yes, CacheVar = no)
dnl if CacheVar == yes
dnl AC_MESSAGE_RESULT(yes)
dnl ActionPass
dnl else
dnl AC_MESSAGE_RESULT(no)
dnl ActionFail
dnl )
dnl
AC_DEFUN(AC_MSG_TRY_COMPILE, [
AC_CACHE_CHECK($1, $2, [
AC_TRY_COMPILE([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
])
if test "x[$]$2" = "xyes"; then
$5
else
$6
:
fi
])
dnl
dnl AC_MSG_TRY_LINK
dnl
dnl Usage:
dnl AC_MSG_TRY_LINK(Message, CacheVar, Includes, Code,
dnl ActionPass [,ActionFail] )
dnl
dnl as AC_MSG_TRY_COMPILE, but uses AC_TRY_LINK instead of AC_TRY_COMPILE
dnl
AC_DEFUN(AC_MSG_TRY_LINK, [
AC_CACHE_CHECK($1, $2, [
AC_TRY_LINK([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
])
if test "x[$]$2" = "xyes"; then
$5
else
$6
:
fi
])
dnl
dnl AC_LIBRARY_NET: #Id: net.m4,v 1.5 1997/11/09 21:36:54 jhawk Exp #
dnl
dnl Written by John Hawkinson <jhawk@mit.edu>. This code is in the Public
dnl Domain.
dnl
dnl This test is for network applications that need socket() and
dnl gethostbyname() -ish functions. Under Solaris, those applications need to
dnl link with "-lsocket -lnsl". Under IRIX, they should *not* link with
dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
dnl IRIX).
dnl
dnl Unfortunately, many application developers are not aware of this, and
dnl mistakenly write tests that cause -lsocket to be used under IRIX. It is
dnl also easy to write tests that cause -lnsl to be used under operating
dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
dnl uses -lnsl for TLI.
dnl
dnl This test exists so that every application developer does not test this in
dnl a different, and subtly broken fashion.
dnl
dnl It has been argued that this test should be broken up into two separate
dnl tests, one for the resolver libraries, and one for the libraries necessary
dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
dnl allowing the autoconf user to use them independently potentially results in
dnl unfortunate ordering dependencies -- as such, such component macros would
dnl have to carefully use indirection and be aware if the other components were
dnl executed. Since other autoconf macros do not go to this trouble, and almost
dnl no applications use sockets without the resolver, this complexity has not
dnl been implemented.
dnl
dnl The check for libresolv is in case you are attempting to link statically
dnl and happen to have a libresolv.a lying around (and no libnsl.a).
dnl
AC_DEFUN(AC_LIBRARY_NET, [
# Most operating systems have gethostbyname() in the default searched
# libraries (i.e. libc):
AC_CHECK_FUNC(gethostbyname, ,
# Some OSes (eg. Solaris) place it in libnsl:
AC_CHECK_LIB(nsl, gethostbyname, ,
# Some strange OSes (SINIX) have it in libsocket:
AC_CHECK_LIB(socket, gethostbyname, ,
# Unfortunately libsocket sometimes depends on libnsl.
# AC_CHECK_LIB's API is essentially broken so the following
# ugliness is necessary:
AC_CHECK_LIB(socket, gethostbyname,
LIBS="-lsocket -lnsl $LIBS",
AC_CHECK_LIB(resolv, gethostbyname),
-lnsl)
)
)
)
AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
])
dnl From heimdal sources
dnl Id: c-attribute.m4,v 1.5 2004/08/26 12:35:41 joda Exp
dnl
dnl
dnl Test for __attribute__
dnl
AC_DEFUN([AC_C___ATTRIBUTE__], [
AC_MSG_CHECKING(for __attribute__)
AC_CACHE_VAL(ac_cv___attribute__, [
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
static void foo(void) __attribute__ ((noreturn));
static void
foo(void)
{
exit(1);
}
]])],
[ac_cv___attribute__=yes],
[ac_cv___attribute__=no])])
if test "$ac_cv___attribute__" = "yes"; then
AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__])
fi
AC_MSG_RESULT($ac_cv___attribute__)
])

View File

@@ -0,0 +1,113 @@
/* $NetBSD: asprintf.c,v 1.3 2012/07/02 16:02:53 joerg Exp $ */
/*-
* Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
int
asprintf(char **ret, const char *fmt, ...)
{
va_list ap;
int retval;
va_start(ap, fmt);
retval = vasprintf(ret, fmt, ap);
va_end(ap);
return retval;
}
int
vasprintf(char **ret, const char *fmt, va_list ap)
{
char *buf, *new_buf;
size_t len;
int retval;
va_list ap2;
len = 128;
buf = malloc(len);
if (buf == NULL) {
*ret = NULL;
return -1;
}
#if defined(HAVE_VA_COPY)
va_copy(ap2, ap);
#define my_va_end(ap2) va_end(ap2)
#elif defined(HAVE___BUILTIN_VA_COPY)
__builtin_va_copy(ap2, ap);
#define my_va_end(ap2) __builtin_va_end(ap2)
#else
ap2 = ap;
#define my_va_end(ap2) do {} while (0)
#endif
retval = vsnprintf(buf, len, fmt, ap);
if (retval < 0) {
free(buf);
*ret = NULL;
va_end(ap2);
return -1;
}
if (retval < len) {
new_buf = realloc(buf, retval + 1);
if (new_buf == NULL)
*ret = buf;
else
*ret = new_buf;
my_va_end(ap2);
return retval;
}
len = (size_t)retval + 1;
free(buf);
buf = malloc(len);
if (buf == NULL) {
*ret = NULL;
my_va_end(ap2);
return -1;
}
retval = vsnprintf(buf, len, fmt, ap2);
my_va_end(ap2);
if (retval != len - 1) {
free(buf);
*ret = NULL;
return -1;
}
*ret = buf;
return retval;
}

1502
pkgtools/libnbcompat/files/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1708
pkgtools/libnbcompat/files/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

8449
pkgtools/libnbcompat/files/configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,560 @@
dnl $NetBSD: configure.ac,v 1.80 2013/02/10 12:38:52 obache Exp $
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.52)
AC_INIT([libnbcompat], [20120702], [joerg@NetBSD.org])
AC_CONFIG_HEADER(nbcompat/config.h)
AC_ARG_PROGRAM
AC_CANONICAL_HOST
CANONICAL_HOST=$host
AC_SUBST(CANONICAL_HOST)
AC_SUBST(INCLUDES)
# Checks for programs.
AC_PROG_MAKE_SET
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_RANLIB
AC_PROG_AWK
AC_CHECK_PROG(AR, ar, ar)
AUTOCONF=${AUTOCONF-"$srcdir/missing --run autoconf"}
AC_SUBST(AUTOCONF)
AUTOHEADER=${AUTOHEADER-"$srcdir/missing --run autoheader"}
AC_SUBST(AUTOHEADER)
dnl Checks for libraries
AC_CHECK_LIB(util, fparseln)
dnl Checks for header files.
AC_HEADER_STDC
AC_HEADER_TIME
AC_HEADER_STDBOOL
AC_CHECK_HEADERS([alloca.h assert.h ctype.h dirent.h endian.h err.h errno.h \
fcntl.h fnmatch.h fts.h grp.h inttypes.h libutil.h limits.h \
machine/endian.h ndir.h netdb.h paths.h pwd.h signal.h \
stdarg.h stddef.h stdint.h stdio.h \
stdlib.h string.h sys/byteorder.h sys/cdefs.h sys/dir.h sys/endian.h \
sys/file.h sys/mkdev.h sys/ndir.h sys/param.h sys/socket.h sys/stat.h \
sys/statfs.h sys/statvfs.h sys/time.h sys/ttycom.h sys/types.h \
sys/uio.h sys/vfs.h sysexits.h termcap.h time.h tzfile.h unistd.h \
util.h utime.h
])
AC_CHECK_HEADERS([sys/mount.h], [:], [:], [
AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
])
dnl Always use our own glob().
AC_CHECK_HEADERS([glob.h])
AC_DEFINE(HAVE_NBCOMPAT_GLOB)
AH_TEMPLATE([HAVE_NBCOMPAT_GLOB], [
Define to 1 if the `glob' function is built into the library.
])
AC_LIBOBJ(glob)
dnl Always use our own queue(3) implementation.
AC_CHECK_HEADERS([sys/queue.h])
AC_DEFINE(HAVE_NBCOMPAT_QUEUE)
AH_TEMPLATE([HAVE_NBCOMPAT_QUEUE], [
Define to 1 if the `queue' macros are supplied by the library.
])
AC_CHECK_HEADERS([regex.h])
AC_CHECK_FUNC(regexec, [:], [
AC_DEFINE(HAVE_NBCOMPAT_REGEX)
AH_TEMPLATE([HAVE_NBCOMPAT_REGEX], [
Define to 1 if the `regex' functions are built into the
library.
])
AC_LIBOBJ(regcomp)
AC_LIBOBJ(regerror)
AC_LIBOBJ(regexec)
AC_LIBOBJ(regfree)
])
AC_MSG_TRY_LINK([for va_copy], pkg_cv_have_va_copy, [
#include <stdarg.h>
], [
va_list ap, ap2;
va_copy(ap2, ap);
return 0;
], AC_DEFINE(HAVE_VA_COPY)
AH_TEMPLATE([HAVE_VA_COPY], [
Define to 1 if the `va_copy' function is supported.
]), [:]
])
AC_MSG_TRY_LINK([for __builtin_va_copy], pkg_cv_have___builtin_va_copy, [
#include <stdarg.h>
], [
va_list ap, ap2;
__builtin_va_copy(ap2, ap);
return 0;
], AC_DEFINE(HAVE___BUILTIN_VA_COPY)
AH_TEMPLATE([HAVE___BUILTIN_VA_COPY], [
Define to 1 if the `__builtin_va_copy' function is supported.
]), [:]
])
AC_CHECK_HEADERS([md5.h], [
AC_MSG_TRY_COMPILE([for MD5Init in md5.h], pkg_cv_have_md5init, [
#include <sys/types.h>
#include <md5.h>
], [
MD5_CTX *f;
MD5Init(f);
], [:], [
AC_DEFINE(HAVE_NBCOMPAT_MD5INIT)
AH_TEMPLATE([HAVE_NBCOMPAT_MD5INIT], [
Define to 1 if the `MD5Init' function is built into
the library.
])
])
])
AC_CHECK_HEADERS([md5.h rmd160.h sha1.h sha2.h])
AC_CHECK_FUNC(MD5File, [:], [
AC_DEFINE(HAVE_NBCOMPAT_MD5)
AH_TEMPLATE([HAVE_NBCOMPAT_MD5], [
Define to 1 if the `MD5*' functions are built into the
library.
])
AC_LIBOBJ(md5c)
AC_LIBOBJ(md5hl)
])
AC_CHECK_FUNC(RMD160File, [:], [
AC_DEFINE(HAVE_NBCOMPAT_RMD160)
AH_TEMPLATE([HAVE_NBCOMPAT_RMD160], [
Define to 1 if the `RMD160*' functions are built into the
library.
])
AC_LIBOBJ(rmd160)
AC_LIBOBJ(rmd160hl)
])
AC_CHECK_FUNC(SHA1File, [:], [
AC_DEFINE(HAVE_NBCOMPAT_SHA1)
AH_TEMPLATE([HAVE_NBCOMPAT_SHA1], [
Define to 1 if the `SHA1*' functions are built into the
library.
])
AC_LIBOBJ(sha1)
AC_LIBOBJ(sha1hl)
])
AC_CHECK_FUNC(SHA512_File, [:], [
AC_DEFINE(HAVE_NBCOMPAT_SHA2)
AH_TEMPLATE([HAVE_NBCOMPAT_SHA2], [
Define to 1 if the `SHA2*' functions are built into the
library.
])
AC_LIBOBJ(sha2)
AC_LIBOBJ(sha2hl)
])
case $host in
*-*-hpux*)
AC_DEFINE(BROKEN_PREAD)
AH_TEMPLATE([BROKEN_PREAD], [
Define to 1 if the `pread' function is broken.
])
AC_DEFINE(BROKEN_PWRITE)
AH_TEMPLATE([BROKEN_PWRITE], [
Define to 1 if the `pwrite' function is broken.
])
;;
esac
AC_ARG_ENABLE([db],
[AS_HELP_STRING([--enable-db], [include DB implementation])])
AC_SUBST(WITH_DB, $enable_db)
AC_CHECK_FUNCS(issetugid)
AC_ARG_ENABLE([bsd-getopt],
[AS_HELP_STRING([--enable-bsd-getopt],
[force use of BSDish getopt implementation])])
AC_CHECK_DECLS([optarg, optind, optreset], [:], [:], [
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
])
our_getopt_long=no
AC_CHECK_HEADERS([getopt.h],
[ AC_CHECK_TYPES([struct option], [:],
[ our_getopt_long=yes ], [#include <getopt.h>])],
[ our_getopt_long=yes ]
)
if test "$enable_bsd_getopt" = yes; then
if test "$ac_cv_have_decl_optreset" = no; then
AC_MSG_NOTICE([Using included getopt and getopt_long])
AC_LIBOBJ(getopt)
our_getopt_long=yes
fi
fi
if test "$our_getopt_long" = "yes"; then
AC_LIBOBJ(getopt_long)
fi
dnl Check that this vis.h has *vis()-related functions because Solaris'
dnl vis.h doesn't. Also, only consider the header found if it defines
dnl all of the functions that we need.
dnl
pkg_use_nbcompat_vis=yes
AC_CHECK_HEADERS([vis.h], [
AC_MSG_TRY_COMPILE([for VIS_WHITE in vis.h], pkg_cv_have_vis_white, [
#include <sys/types.h>
#include <vis.h>
], [ int X = VIS_WHITE; ], [
AC_CHECK_FUNCS([strunvis strvis strsvis svis unvis vis])
AC_CHECK_FUNCS([strunvis strvis strsvis svis unvis vis],
[pkg_use_nbcompat_vis=no],
[pkg_use_nbcompat_vis=yes; break])
])
])
if test $pkg_use_nbcompat_vis = yes; then
AC_DEFINE(HAVE_NBCOMPAT_VIS)
AH_TEMPLATE([HAVE_NBCOMPAT_VIS], [
Define to 1 if the `vis' function is built into the library.
])
AC_LIBOBJ(vis)
AC_LIBOBJ(unvis)
fi
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C___ATTRIBUTE__
AC_TYPE_SIZE_T
AC_TYPE_UINTPTR_T
AC_TYPE_INT8_T
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_CHECK_TYPES([long long, long double],[],[],
[#if STDC_HEADERS
#include <stdlib.h>
#include <stddef.h>
#endif
#if HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_BITYPES_H
#include <sys/bitypes.h>
#endif])
AC_CHECK_TYPES([fsid_t],[],[],
[#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif])
AC_C_BIGENDIAN
AC_CHECK_SIZEOF(off_t, 0)
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_STRERROR_R
AC_FUNC_VFORK
AC_FUNC_VPRINTF
AC_CHECK_DECLS([snprintf, vasprintf], [], [], [#include <stdio.h>])
case $host_os in
darwin*)
# NetBSD PR 38488: warnx(3) escapes certain characters like \n
ac_cv_func_warn=no
;;
esac
AC_REPLACE_FUNCS([asprintf err fgetln fnmatch fparseln getenv isblank \
lchflags lchmod lchown lutimes mkdtemp mkstemp setenv setgroupent \
setpassent setprogname shquote snprintf statvfs strdup strerror \
strlcat strlcpy strmode strsep strtoll unsetenv usleep utimes warn
])
AC_SEARCH_LIBS(socket, [socket network])
AC_CHECK_LIB(nsl, gethostbyname)
need_getaddrinfo=no
AC_CHECK_TYPES([socklen_t], [], [], [[#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/socket.h>
]])
AC_CHECK_TYPES([struct addrinfo], [], [], [[#include <netdb.h>]])
AC_CHECK_TYPES([struct in6_addr], [], [], [[#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
]])
AC_CHECK_TYPES([struct sockaddr_in6], [], [], [[#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <netinet/in.h>
]])
AC_CHECK_TYPES([struct sockaddr_storage], [], [], [[#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/socket.h>
]])
dnl Assume that freeaddrinfo is only missing if getaddrinfo is also missing
AC_CHECK_FUNCS([getnameinfo gai_strerror getaddrinfo], [:],
[need_getaddrinfo=yes])
if test $need_getaddrinfo = yes; then
AC_LIBOBJ(getaddrinfo)
fi
need_findenv=no
AC_CHECK_FUNCS([getenv setenv unsetenv], [:], [need_findenv=yes])
if test $need_findenv = yes; then
AC_LIBOBJ(findenv)
fi
need_gettemp=no
AC_CHECK_FUNCS([mkdtemp mkstemp], [:], [ need_gettemp=yes ])
if test $need_gettemp = yes; then
AC_LIBOBJ(gettemp)
fi
AC_CHECK_FUNCS([bcopy bzero memset memcpy setlocale])
need_setmode=no
AC_CHECK_FUNCS([getmode setmode], [:], [need_setmode=yes])
if test $need_setmode = yes; then
AC_LIBOBJ(setmode)
fi
AC_CHECK_DECLS([endgrent, endpwent, setpassent])
need_pwcache=no
AC_CHECK_FUNCS([gid_from_group group_from_gid pwcache_groupdb \
pwcache_userdb uid_from_user user_from_uid \
], [:], [need_pwcache=yes])
if test $need_pwcache = yes; then
AC_LIBOBJ(pwcache)
fi
AC_CHECK_FUNC(fts_open, [:], [
AC_DEFINE(HAVE_NBCOMPAT_FTS, 1)
AH_TEMPLATE([HAVE_NBCOMPAT_FTS], [
Define to 1 if the `fts_*' functions are built into the
library.
])
AC_LIBOBJ(fts)
])
AC_CHECK_FUNC(timegm, [:], [AC_LIBOBJ(timegm)])
# Handle Darwin 7 having a poll() compatibility function. Be
# conservative -- if we don't find one of <poll.h> or <sys/poll.h>, then
# use our own poll() implementation.
#
pkg_cv_have_poll_h=no
AC_CHECK_HEADERS([poll.h sys/poll.h])
AC_CHECK_HEADERS([poll.h sys/poll.h], [pkg_cv_have_poll_h=yes])
pkg_use_nbcompat_poll=yes
if test $pkg_cv_have_poll_h = yes; then
pkg_use_nbcompat_poll=no
fi
if test $pkg_cv_have_poll_h = yes -o test $pkg_cv_have_sys_poll_h = yes; then
AC_CHECK_FUNC(poll, [
AC_MSG_TRY_COMPILE([if poll() is implemented natively],
pkg_cv_native_poll,
[ #if HAVE_POLL_H
#include <poll.h>
#endif
#if HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
],
[ #ifdef _POLL_EMUL_H_
#error "poll() is emulated"
#endif
],
[pkg_use_nbcompat_poll=no],
[pkg_use_nbcompat_poll=yes])
])
fi
if test $pkg_use_nbcompat_poll = yes; then
AC_DEFINE(HAVE_NBCOMPAT_POLL, 1)
AH_TEMPLATE([HAVE_NBCOMPAT_POLL], [
Define to 1 if the `poll' function is built into the library.
])
AC_LIBOBJ(poll)
fi
AC_CHECK_FUNCS([getpassphrase getpgrp memmove select])
AC_CHECK_FUNC(getpgrp, [AC_FUNC_GETPGRP])
AC_CHECK_MEMBERS([struct statfs.f_flags], [:], [:],
[ #include <sys/statfs.h> ])
AC_CHECK_MEMBERS([struct statfs.f_fsize], [:], [:],
[ #include <sys/statfs.h> ])
AC_CHECK_MEMBERS([struct statfs.f_iosize], [:], [:],
[ #include <sys/statfs.h> ])
AC_CHECK_MEMBERS([struct dirent.d_namlen, DIR.dd_fd], [:], [:],
[ #include <sys/types.h>
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif ])
AC_MSG_CHECKING([for dirfd])
AC_TRY_LINK(
[ #include <sys/types.h>
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
int dummy_var;
], [ dummy_var = dirfd((DIR *)0) ],
[
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_DIRFD], [1], [Define if dirfd is either a function or a macro.])
], [ AC_MSG_RESULT(no) ]
)
if test $ac_cv_type_long_long = yes; then
dnl We assume that if sprintf() supports %lld or %qd,
dnl then all of *printf() does. If not, disable long long
dnl support because we don't know how to display it.
AC_MSG_CHECKING(*printf() support for %lld)
can_printf_longlong=no
AC_TRY_RUN([
#include <stdio.h>
int main() {
char buf[100];
sprintf(buf, "%lld", 4294967300LL);
return (strcmp(buf, "4294967300"));
}
], [
AC_MSG_RESULT(yes)
can_printf_longlong=yes
], [
AC_MSG_RESULT(no)
], [:])
if test $can_printf_longlong != yes; then
AC_MSG_CHECKING(*printf() support for %qd)
AC_TRY_RUN([
#include <stdio.h>
int main() {
char buf[100];
sprintf(buf, "%qd", 4294967300LL);
return (strcmp(buf, "4294967300"));
}
], [
AC_MSG_RESULT(yes)
can_printf_longlong=yes
AC_DEFINE(HAVE_PRINTF_QD, 1)
AH_TEMPLATE([HAVE_PRINTF_QD], [
Define to 1 if *printf() uses %qd to print
`long long' (otherwise uses %lld).
])
], [
AC_MSG_RESULT(no)
], [:])
fi
if test $can_printf_longlong = yes; then
AC_DEFINE(HAVE_WORKING_LONG_LONG, 1)
AH_TEMPLATE([HAVE_WORKING_LONG_LONG], [
Define to 1 if `long long' is supported and
sizeof(off_t) >= 8.
])
AC_REPLACE_FUNCS(strtoll)
fi
fi
dnl Check if vsnprintf returns the number of bytes that would have been
dnl written, had the buffer been large enough.
AC_MSG_CHECKING(if vsnprintf is standards compliant)
have_std_vsnprintf=no
AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void dotest(char *fmt, ...) {
char buf[3];
va_list ap;
va_start(ap, fmt);
exit(snprintf(buf, 3, fmt, ap) == 4 ? 0 : 1);
}
int main() {
dotest("test");
}
], [
AC_MSG_RESULT(yes)
have_std_vsnprintf=yes
], [
AC_MSG_RESULT(no)
], [:])
if test $have_std_vsnprintf = no; then
AC_LIBOBJ(snprintf)
fi
AH_BOTTOM([
/* NBCOMPAT template section follows. */
#ifndef HAVE___ATTRIBUTE__
# define __attribute__(x)
#endif
])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@@ -0,0 +1,17 @@
# $NetBSD: Makefile.inc,v 1.1 2008/10/10 00:21:43 joerg Exp $
.PATH: ${.PARSEDIR}/btree ${.PARSEDIR}/db ${.PARSEDIR}/hash \
${.PARSEDIR}/mpool ${.PARSEDIR}/recno
CPPFLAGS+=-D__DBINTERFACE_PRIVATE
OBJS+= bt_close.o bt_conv.o bt_debug.o bt_delete.o bt_get.o bt_open.o \
bt_overflow.o bt_page.o bt_put.o bt_search.o bt_seq.o bt_split.o \
bt_utils.o \
db.o \
hash.o hash_bigkey.o hash_buf.o hash_func.o hash_log2.o hash_page.o \
ndbm.o ndbmdatum.o \
mpool.o rec_close.o rec_delete.o rec_get.o rec_open.o rec_put.o \
rec_search.o rec_seq.o rec_utils.o
INCS+= nbcompat/db.h

View File

@@ -0,0 +1,177 @@
/* $NetBSD: bt_close.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_close.c,v 1.14 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_close.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nbcompat/db.h>
#include "btree.h"
static int bt_meta(BTREE *);
/*
* BT_CLOSE -- Close a btree.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__bt_close(DB *dbp)
{
BTREE *t;
int fd;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Sync the tree. */
if (__bt_sync(dbp, 0) == RET_ERROR)
return (RET_ERROR);
/* Close the memory pool. */
if (mpool_close(t->bt_mp) == RET_ERROR)
return (RET_ERROR);
/* Free random memory. */
if (t->bt_cursor.key.data != NULL) {
free(t->bt_cursor.key.data);
t->bt_cursor.key.size = 0;
t->bt_cursor.key.data = NULL;
}
if (t->bt_rkey.data) {
free(t->bt_rkey.data);
t->bt_rkey.size = 0;
t->bt_rkey.data = NULL;
}
if (t->bt_rdata.data) {
free(t->bt_rdata.data);
t->bt_rdata.size = 0;
t->bt_rdata.data = NULL;
}
fd = t->bt_fd;
free(t);
free(dbp);
return (close(fd) ? RET_ERROR : RET_SUCCESS);
}
/*
* BT_SYNC -- sync the btree to disk.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_sync(const DB *dbp, u_int flags)
{
BTREE *t;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Sync doesn't currently take any flags. */
if (flags != 0) {
errno = EINVAL;
return (RET_ERROR);
}
if (F_ISSET(t, B_INMEM | B_RDONLY) || !F_ISSET(t, B_MODIFIED))
return (RET_SUCCESS);
if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR)
return (RET_ERROR);
if ((status = mpool_sync(t->bt_mp)) == RET_SUCCESS)
F_CLR(t, B_MODIFIED);
return (status);
}
/*
* BT_META -- write the tree meta data to disk.
*
* Parameters:
* t: tree
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_meta(BTREE *t)
{
BTMETA m;
void *p;
if ((p = mpool_get(t->bt_mp, P_META, 0)) == NULL)
return (RET_ERROR);
/* Fill in metadata. */
m.magic = BTREEMAGIC;
m.version = BTREEVERSION;
m.psize = t->bt_psize;
m.free = t->bt_free;
m.nrecs = t->bt_nrecs;
m.flags = F_ISSET(t, SAVEMETA);
memmove(p, &m, sizeof(BTMETA));
mpool_put(t->bt_mp, p, MPOOL_DIRTY);
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,213 @@
/* $NetBSD: bt_conv.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_conv.c,v 1.14 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_conv.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <assert.h>
#include <stdio.h>
#include <nbcompat/db.h>
#include "btree.h"
static void mswap(PAGE *);
/*
* __BT_BPGIN, __BT_BPGOUT --
* Convert host-specific number layout to/from the host-independent
* format stored on disk.
*
* Parameters:
* t: tree
* pg: page number
* h: page to convert
*/
void
__bt_pgin(void *t, pgno_t pg, void *pp)
{
PAGE *h;
indx_t i, top;
uint8_t flags;
char *p;
if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
return;
if (pg == P_META) {
mswap(pp);
return;
}
h = pp;
M_32_SWAP(h->pgno);
M_32_SWAP(h->prevpg);
M_32_SWAP(h->nextpg);
M_32_SWAP(h->flags);
M_16_SWAP(h->lower);
M_16_SWAP(h->upper);
top = NEXTINDEX(h);
if ((h->flags & P_TYPE) == P_BINTERNAL)
for (i = 0; i < top; i++) {
M_16_SWAP(h->linp[i]);
p = (char *)(void *)GETBINTERNAL(h, i);
P_32_SWAP(p);
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
if (*(uint8_t *)p & P_BIGKEY) {
p += sizeof(uint8_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
else if ((h->flags & P_TYPE) == P_BLEAF)
for (i = 0; i < top; i++) {
M_16_SWAP(h->linp[i]);
p = (char *)(void *)GETBLEAF(h, i);
P_32_SWAP(p);
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(uint32_t);
flags = *(uint8_t *)p;
if (flags & (P_BIGKEY | P_BIGDATA)) {
p += sizeof(uint8_t);
if (flags & P_BIGKEY) {
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
if (flags & P_BIGDATA) {
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
}
}
void
__bt_pgout(void *t, pgno_t pg, void *pp)
{
PAGE *h;
indx_t i, top;
uint8_t flags;
char *p;
if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
return;
if (pg == P_META) {
mswap(pp);
return;
}
h = pp;
top = NEXTINDEX(h);
if ((h->flags & P_TYPE) == P_BINTERNAL)
for (i = 0; i < top; i++) {
p = (char *)(void *)GETBINTERNAL(h, i);
P_32_SWAP(p);
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
if (*(uint8_t *)p & P_BIGKEY) {
p += sizeof(uint8_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
M_16_SWAP(h->linp[i]);
}
else if ((h->flags & P_TYPE) == P_BLEAF)
for (i = 0; i < top; i++) {
p = (char *)(void *)GETBLEAF(h, i);
P_32_SWAP(p);
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(uint32_t);
flags = *(uint8_t *)p;
if (flags & (P_BIGKEY | P_BIGDATA)) {
p += sizeof(uint8_t);
if (flags & P_BIGKEY) {
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
if (flags & P_BIGDATA) {
p += sizeof(uint32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
M_16_SWAP(h->linp[i]);
}
M_32_SWAP(h->pgno);
M_32_SWAP(h->prevpg);
M_32_SWAP(h->nextpg);
M_32_SWAP(h->flags);
M_16_SWAP(h->lower);
M_16_SWAP(h->upper);
}
/*
* MSWAP -- Actually swap the bytes on the meta page.
*
* Parameters:
* p: page to convert
*/
static void
mswap(PAGE *pg)
{
char *p;
p = (char *)(void *)pg;
P_32_SWAP(p); /* magic */
p += sizeof(uint32_t);
P_32_SWAP(p); /* version */
p += sizeof(uint32_t);
P_32_SWAP(p); /* psize */
p += sizeof(uint32_t);
P_32_SWAP(p); /* free */
p += sizeof(uint32_t);
P_32_SWAP(p); /* nrecs */
p += sizeof(uint32_t);
P_32_SWAP(p); /* flags */
p += sizeof(uint32_t);
}

View File

@@ -0,0 +1,323 @@
/* $NetBSD: bt_debug.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_debug.c,v 1.15 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_debug.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
#ifdef DEBUG
/*
* BT_DUMP -- Dump the tree
*
* Parameters:
* dbp: pointer to the DB
*/
void
__bt_dump(DB *dbp)
{
BTREE *t;
PAGE *h;
pgno_t i;
const char *sep;
t = dbp->internal;
(void)fprintf(stderr, "%s: pgsz %d",
F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
if (F_ISSET(t, R_RECNO))
(void)fprintf(stderr, " keys %lu", (unsigned long) t->bt_nrecs);
#undef X
#define X(flag, name) \
if (F_ISSET(t, flag)) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
if (t->flags != 0) {
sep = " flags (";
X(R_FIXLEN, "FIXLEN");
X(B_INMEM, "INMEM");
X(B_NODUPS, "NODUPS");
X(B_RDONLY, "RDONLY");
X(R_RECNO, "RECNO");
X(B_METADIRTY,"METADIRTY");
(void)fprintf(stderr, ")\n");
}
#undef X
for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
__bt_dpage(h);
(void)mpool_put(t->bt_mp, h, 0);
}
}
/*
* BT_DMPAGE -- Dump the meta page
*
* Parameters:
* h: pointer to the PAGE
*/
void
__bt_dmpage(PAGE *h)
{
BTMETA *m;
const char *sep;
m = (BTMETA *)(void *)h;
(void)fprintf(stderr, "magic %lx\n", (unsigned long) m->magic);
(void)fprintf(stderr, "version %lu\n", (unsigned long) m->version);
(void)fprintf(stderr, "psize %lu\n", (unsigned long) m->psize);
(void)fprintf(stderr, "free %lu\n", (unsigned long) m->free);
(void)fprintf(stderr, "nrecs %lu\n", (unsigned long) m->nrecs);
(void)fprintf(stderr, "flags %lu", (unsigned long) m->flags);
#undef X
#define X(flag, name) \
if (m->flags & flag) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
if (m->flags) {
sep = " (";
X(B_NODUPS, "NODUPS");
X(R_RECNO, "RECNO");
(void)fprintf(stderr, ")");
}
}
/*
* BT_DNPAGE -- Dump the page
*
* Parameters:
* n: page number to dump.
*/
void
__bt_dnpage(DB *dbp, pgno_t pgno)
{
BTREE *t;
PAGE *h;
t = dbp->internal;
if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) {
__bt_dpage(h);
(void)mpool_put(t->bt_mp, h, 0);
}
}
/*
* BT_DPAGE -- Dump the page
*
* Parameters:
* h: pointer to the PAGE
*/
void
__bt_dpage(PAGE *h)
{
BINTERNAL *bi;
BLEAF *bl;
RINTERNAL *ri;
RLEAF *rl;
indx_t cur, top;
const char *sep;
(void)fprintf(stderr, " page %d: (", h->pgno);
#undef X
#define X(flag, name) \
if (h->flags & flag) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
sep = "";
X(P_BINTERNAL, "BINTERNAL") /* types */
X(P_BLEAF, "BLEAF")
X(P_RINTERNAL, "RINTERNAL") /* types */
X(P_RLEAF, "RLEAF")
X(P_OVERFLOW, "OVERFLOW")
X(P_PRESERVE, "PRESERVE");
(void)fprintf(stderr, ")\n");
#undef X
(void)fprintf(stderr, "\tprev %2d next %2d", h->prevpg, h->nextpg);
if (h->flags & P_OVERFLOW)
return;
top = NEXTINDEX(h);
(void)fprintf(stderr, " lower %3d upper %3d nextind %d\n",
h->lower, h->upper, top);
for (cur = 0; cur < top; cur++) {
(void)fprintf(stderr, "\t[%03d] %4d ", cur, h->linp[cur]);
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
bi = GETBINTERNAL(h, cur);
(void)fprintf(stderr,
"size %03d pgno %03d", bi->ksize, bi->pgno);
if (bi->flags & P_BIGKEY)
(void)fprintf(stderr, " (indirect)");
else if (bi->ksize)
(void)fprintf(stderr,
" {%.*s}", (int)bi->ksize, bi->bytes);
break;
case P_RINTERNAL:
ri = GETRINTERNAL(h, cur);
(void)fprintf(stderr, "entries %03d pgno %03d",
ri->nrecs, ri->pgno);
break;
case P_BLEAF:
bl = GETBLEAF(h, cur);
if (bl->flags & P_BIGKEY)
(void)fprintf(stderr,
"big key page %lu size %u/",
(unsigned long) *(pgno_t *)(void *)bl->bytes,
*(uint32_t *)(void *)(bl->bytes + sizeof(pgno_t)));
else if (bl->ksize)
(void)fprintf(stderr, "%s/", bl->bytes);
if (bl->flags & P_BIGDATA)
(void)fprintf(stderr,
"big data page %lu size %u",
(unsigned long) *(pgno_t *)(void *)(bl->bytes + bl->ksize),
*(uint32_t *)(void *)(bl->bytes + bl->ksize +
sizeof(pgno_t)));
else if (bl->dsize)
(void)fprintf(stderr, "%.*s",
(int)bl->dsize, bl->bytes + bl->ksize);
break;
case P_RLEAF:
rl = GETRLEAF(h, cur);
if (rl->flags & P_BIGDATA)
(void)fprintf(stderr,
"big data page %lu size %u",
(unsigned long) *(pgno_t *)(void *)rl->bytes,
*(uint32_t *)(void *)(rl->bytes + sizeof(pgno_t)));
else if (rl->dsize)
(void)fprintf(stderr,
"%.*s", (int)rl->dsize, rl->bytes);
break;
}
(void)fprintf(stderr, "\n");
}
}
#endif
#ifdef STATISTICS
/*
* BT_STAT -- Gather/print the tree statistics
*
* Parameters:
* dbp: pointer to the DB
*/
void
__bt_stat(DB *dbp)
{
extern unsigned long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
extern unsigned long bt_sortsplit, bt_split;
BTREE *t;
PAGE *h;
pgno_t i, pcont, pinternal, pleaf;
unsigned long ifree, lfree, nkeys;
int levels;
t = dbp->internal;
pcont = pinternal = pleaf = 0;
nkeys = ifree = lfree = 0;
for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
case P_RINTERNAL:
++pinternal;
ifree += h->upper - h->lower;
break;
case P_BLEAF:
case P_RLEAF:
++pleaf;
lfree += h->upper - h->lower;
nkeys += NEXTINDEX(h);
break;
case P_OVERFLOW:
++pcont;
break;
}
(void)mpool_put(t->bt_mp, h, 0);
}
/* Count the levels of the tree. */
for (i = P_ROOT, levels = 0 ;; ++levels) {
h = mpool_get(t->bt_mp, i, 0);
if (h->flags & (P_BLEAF|P_RLEAF)) {
if (levels == 0)
levels = 1;
(void)mpool_put(t->bt_mp, h, 0);
break;
}
i = F_ISSET(t, R_RECNO) ?
GETRINTERNAL(h, 0)->pgno :
GETBINTERNAL(h, 0)->pgno;
(void)mpool_put(t->bt_mp, h, 0);
}
(void)fprintf(stderr, "%d level%s with %ld keys",
levels, levels == 1 ? "" : "s", nkeys);
if (F_ISSET(t, R_RECNO))
(void)fprintf(stderr, " (%ld header count)", (long)t->bt_nrecs);
(void)fprintf(stderr,
"\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
(long)pinternal + pleaf + pcont, (long)pleaf, (long)pinternal,
(long)pcont);
(void)fprintf(stderr, "%ld cache hits, %ld cache misses\n",
bt_cache_hit, bt_cache_miss);
(void)fprintf(stderr, "%ld splits (%ld root splits, %ld sort splits)\n",
bt_split, bt_rootsplit, bt_sortsplit);
pleaf *= t->bt_psize - BTDATAOFF;
if (pleaf)
(void)fprintf(stderr,
"%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n",
((double)(pleaf - lfree) / pleaf) * 100,
pleaf - lfree, lfree);
pinternal *= t->bt_psize - BTDATAOFF;
if (pinternal)
(void)fprintf(stderr,
"%.0f%% internal fill (%ld bytes used, %ld bytes free\n",
((double)(pinternal - ifree) / pinternal) * 100,
pinternal - ifree, ifree);
if (bt_pfxsaved)
(void)fprintf(stderr, "prefix checking removed %lu bytes.\n",
bt_pfxsaved);
}
#endif

View File

@@ -0,0 +1,640 @@
/* $NetBSD: bt_delete.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_delete.c,v 1.16 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_delete.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
static int __bt_bdelete(BTREE *, const DBT *);
static int __bt_curdel(BTREE *, const DBT *, PAGE *, u_int);
static int __bt_pdelete(BTREE *, PAGE *);
static int __bt_relink(BTREE *, PAGE *);
static int __bt_stkacq(BTREE *, PAGE **, CURSOR *);
/*
* __bt_delete
* Delete the item(s) referenced by a key.
*
* Return RET_SPECIAL if the key is not found.
*/
int
__bt_delete(const DB *dbp, const DBT *key, u_int flags)
{
BTREE *t;
CURSOR *c;
PAGE *h;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Check for change to a read-only tree. */
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
status = __bt_bdelete(t, key);
break;
case R_CURSOR:
/*
* If flags is R_CURSOR, delete the cursor. Must already
* have started a scan and not have already deleted it.
*/
c = &t->bt_cursor;
if (F_ISSET(c, CURS_INIT)) {
if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* If the page is about to be emptied, we'll need to
* delete it, which means we have to acquire a stack.
*/
if (NEXTINDEX(h) == 1)
if (__bt_stkacq(t, &h, &t->bt_cursor))
return (RET_ERROR);
status = __bt_dleaf(t, NULL, h, (u_int)c->pg.index);
if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp, h,
(u_int)(status == RET_SUCCESS ?
MPOOL_DIRTY : 0));
break;
}
/* FALLTHROUGH */
default:
errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS)
F_SET(t, B_MODIFIED);
return (status);
}
/*
* __bt_stkacq --
* Acquire a stack so we can delete a cursor entry.
*
* Parameters:
* t: tree
* hp: pointer to current, pinned PAGE pointer
* c: pointer to the cursor
*
* Returns:
* 0 on success, 1 on failure
*/
static int
__bt_stkacq(BTREE *t, PAGE **hp, CURSOR *c)
{
BINTERNAL *bi;
EPG *e;
EPGNO *parent;
PAGE *h;
indx_t idx = 0; /* Pacify gcc */
pgno_t pgno;
recno_t nextpg, prevpg;
int exact, level;
/*
* Find the first occurrence of the key in the tree. Toss the
* currently locked page so we don't hit an already-locked page.
*/
h = *hp;
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/* See if we got it in one shot. */
if (h->pgno == c->pg.pgno)
goto ret;
/*
* Move right, looking for the page. At each move we have to move
* up the stack until we don't have to move to the next page. If
* we have to change pages at an internal level, we have to fix the
* stack back up.
*/
while (h->pgno != c->pg.pgno) {
if ((nextpg = h->nextpg) == P_INVALID)
break;
mpool_put(t->bt_mp, h, 0);
/* Move up the stack. */
for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (1);
/* Move to the next index. */
if (parent->index != NEXTINDEX(h) - 1) {
idx = parent->index + 1;
BT_PUSH(t, h->pgno, idx);
break;
}
mpool_put(t->bt_mp, h, 0);
}
/* Restore the stack. */
while (level--) {
/* Push the next level down onto the stack. */
bi = GETBINTERNAL(h, idx);
pgno = bi->pgno;
BT_PUSH(t, pgno, 0);
/* Lose the currently pinned page. */
mpool_put(t->bt_mp, h, 0);
/* Get the next level down. */
if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
return (1);
idx = 0;
}
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
return (1);
}
if (h->pgno == c->pg.pgno)
goto ret;
/* Reacquire the original stack. */
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/*
* Move left, looking for the page. At each move we have to move
* up the stack until we don't have to change pages to move to the
* next page. If we have to change pages at an internal level, we
* have to fix the stack back up.
*/
while (h->pgno != c->pg.pgno) {
if ((prevpg = h->prevpg) == P_INVALID)
break;
mpool_put(t->bt_mp, h, 0);
/* Move up the stack. */
for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (1);
/* Move to the next index. */
if (parent->index != 0) {
idx = parent->index - 1;
BT_PUSH(t, h->pgno, idx);
break;
}
mpool_put(t->bt_mp, h, 0);
}
/* Restore the stack. */
while (level--) {
/* Push the next level down onto the stack. */
bi = GETBINTERNAL(h, idx);
pgno = bi->pgno;
/* Lose the currently pinned page. */
mpool_put(t->bt_mp, h, 0);
/* Get the next level down. */
if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
return (1);
idx = NEXTINDEX(h) - 1;
BT_PUSH(t, pgno, idx);
}
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
return (1);
}
ret: mpool_put(t->bt_mp, h, 0);
return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
}
/*
* __bt_bdelete --
* Delete all key/data pairs matching the specified key.
*
* Parameters:
* t: tree
* key: key to delete
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
static int
__bt_bdelete(BTREE *t, const DBT *key)
{
EPG *e;
PAGE *h;
int deleted, exact, redo;
deleted = 0;
/* Find any matching record; __bt_search pins the page. */
loop: if ((e = __bt_search(t, key, &exact)) == NULL)
return (deleted ? RET_SUCCESS : RET_ERROR);
if (!exact) {
mpool_put(t->bt_mp, e->page, 0);
return (deleted ? RET_SUCCESS : RET_SPECIAL);
}
/*
* Delete forward, then delete backward, from the found key. If
* there are duplicates and we reach either side of the page, do
* the key search again, so that we get them all.
*/
redo = 0;
h = e->page;
do {
if (__bt_dleaf(t, key, h, (u_int)e->index)) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (F_ISSET(t, B_NODUPS)) {
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
deleted = 1;
} while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
/* Check for right-hand edge of the page. */
if (e->index == NEXTINDEX(h))
redo = 1;
/* Delete from the key to the beginning of the page. */
while (e->index-- > 0) {
if (__bt_cmp(t, key, e) != 0)
break;
if (__bt_dleaf(t, key, h, (u_int)e->index) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (e->index == 0)
redo = 1;
}
/* Check for an empty page. */
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
goto loop;
}
/* Put the page. */
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
if (redo)
goto loop;
return (RET_SUCCESS);
}
/*
* __bt_pdelete --
* Delete a single page from the tree.
*
* Parameters:
* t: tree
* h: leaf page
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side-effects:
* mpool_put's the page
*/
static int
__bt_pdelete(BTREE *t, PAGE *h)
{
BINTERNAL *bi;
PAGE *pg;
EPGNO *parent;
indx_t cnt, idx, *ip, offset;
uint32_t nksize;
char *from;
/*
* Walk the parent page stack -- a LIFO stack of the pages that were
* traversed when we searched for the page where the delete occurred.
* Each stack entry is a page number and a page index offset. The
* offset is for the page traversed on the search. We've just deleted
* a page, so we have to delete the key from the parent page.
*
* If the delete from the parent page makes it empty, this process may
* continue all the way up the tree. We stop if we reach the root page
* (which is never deleted, it's just not worth the effort) or if the
* delete does not empty the page.
*/
while ((parent = BT_POP(t)) != NULL) {
/* Get the parent page. */
if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (RET_ERROR);
idx = parent->index;
bi = GETBINTERNAL(pg, idx);
/* Free any overflow pages. */
if (bi->flags & P_BIGKEY &&
__ovfl_delete(t, bi->bytes) == RET_ERROR) {
mpool_put(t->bt_mp, pg, 0);
return (RET_ERROR);
}
/*
* Free the parent if it has only the one key and it's not the
* root page. If it's the rootpage, turn it back into an empty
* leaf page.
*/
if (NEXTINDEX(pg) == 1) {
if (pg->pgno == P_ROOT) {
pg->lower = BTDATAOFF;
pg->upper = t->bt_psize;
pg->flags = P_BLEAF;
} else {
if (__bt_relink(t, pg) || __bt_free(t, pg))
return (RET_ERROR);
continue;
}
} else {
/* Pack remaining key items at the end of the page. */
nksize = NBINTERNAL(bi->ksize);
from = (char *)(void *)pg + pg->upper;
memmove(from + nksize, from,
(size_t)((char *)(void *)bi - from));
pg->upper += nksize;
/* Adjust indices' offsets, shift the indices down. */
offset = pg->linp[idx];
for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nksize;
for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
pg->lower -= sizeof(indx_t);
}
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
break;
}
/* Free the leaf page, as long as it wasn't the root. */
if (h->pgno == P_ROOT) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
return (__bt_relink(t, h) || __bt_free(t, h));
}
/*
* __bt_dleaf --
* Delete a single record from a leaf page.
*
* Parameters:
* t: tree
* key: referenced key
* h: page
* idx: index on page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_dleaf(BTREE *t, const DBT *key, PAGE *h, u_int idx)
{
BLEAF *bl;
indx_t cnt, *ip, offset;
uint32_t nbytes;
void *to;
char *from;
/* If this record is referenced by the cursor, delete the cursor. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
__bt_curdel(t, key, h, idx))
return (RET_ERROR);
/* If the entry uses overflow pages, make them available for reuse. */
to = bl = GETBLEAF(h, idx);
if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
return (RET_ERROR);
if (bl->flags & P_BIGDATA &&
__ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
return (RET_ERROR);
/* Pack the remaining key/data items at the end of the page. */
nbytes = NBLEAF(bl);
from = (char *)(void *)h + h->upper;
memmove(from + nbytes, from, (size_t)((char *)(void *)to - from));
h->upper += nbytes;
/* Adjust the indices' offsets, shift the indices down. */
offset = h->linp[idx];
for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nbytes;
for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
h->lower -= sizeof(indx_t);
/* If the cursor is on this page, adjust it as necessary. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
--t->bt_cursor.pg.index;
return (RET_SUCCESS);
}
/*
* __bt_curdel --
* Delete the cursor.
*
* Parameters:
* t: tree
* key: referenced key (or NULL)
* h: page
* idx: index on page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
static int
__bt_curdel(BTREE *t, const DBT *key, PAGE *h, u_int idx)
{
CURSOR *c;
EPG e;
PAGE *pg;
int curcopy, status;
/*
* If there are duplicates, move forward or backward to one.
* Otherwise, copy the key into the cursor area.
*/
c = &t->bt_cursor;
F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
curcopy = 0;
if (!F_ISSET(t, B_NODUPS)) {
/*
* We're going to have to do comparisons. If we weren't
* provided a copy of the key, i.e. the user is deleting
* the current cursor position, get one.
*/
if (key == NULL) {
e.page = h;
e.index = idx;
if ((status = __bt_ret(t, &e,
&c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
return (status);
curcopy = 1;
key = &c->key;
}
/* Check previous key, if not at the beginning of the page. */
if (idx > 0) {
e.page = h;
e.index = idx - 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_BEFORE);
goto dup2;
}
}
/* Check next key, if not at the end of the page. */
if (idx < NEXTINDEX(h) - 1) {
e.page = h;
e.index = idx + 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_AFTER);
goto dup2;
}
}
/* Check previous key if at the beginning of the page. */
if (idx == 0 && h->prevpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (RET_ERROR);
e.page = pg;
e.index = NEXTINDEX(pg) - 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_BEFORE);
goto dup1;
}
mpool_put(t->bt_mp, pg, 0);
}
/* Check next key if at the end of the page. */
if (idx == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (RET_ERROR);
e.page = pg;
e.index = 0;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_AFTER);
dup1: mpool_put(t->bt_mp, pg, 0);
dup2: c->pg.pgno = e.page->pgno;
c->pg.index = e.index;
return (RET_SUCCESS);
}
mpool_put(t->bt_mp, pg, 0);
}
}
e.page = h;
e.index = idx;
if (curcopy || (status =
__bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
F_SET(c, CURS_ACQUIRE);
return (RET_SUCCESS);
}
return (status);
}
/*
* __bt_relink --
* Link around a deleted page.
*
* Parameters:
* t: tree
* h: page to be deleted
*/
static int
__bt_relink(BTREE *t, PAGE *h)
{
PAGE *pg;
if (h->nextpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (RET_ERROR);
pg->prevpg = h->prevpg;
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
}
if (h->prevpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (RET_ERROR);
pg->nextpg = h->nextpg;
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
}
return (0);
}

View File

@@ -0,0 +1,102 @@
/* $NetBSD: bt_get.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_get.c,v 1.13 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_get.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <nbcompat/db.h>
#include "btree.h"
/*
* __BT_GET -- Get a record from the btree.
*
* Parameters:
* dbp: pointer to access method
* key: key to find
* data: data to return
* flag: currently unused
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__bt_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG *e;
int exact, status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Get currently doesn't take any flags. */
if (flags) {
errno = EINVAL;
return (RET_ERROR);
}
if ((e = __bt_search(t, key, &exact)) == NULL)
return (RET_ERROR);
if (!exact) {
mpool_put(t->bt_mp, e->page, 0);
return (RET_SPECIAL);
}
status = __bt_ret(t, e, NULL, NULL, data, &t->bt_rdata, 0);
/*
* If the user is doing concurrent access, we copied the
* key/data, toss the page.
*/
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e->page, 0);
else
t->bt_pinned = e->page;
return (status);
}

View File

@@ -0,0 +1,460 @@
/* $NetBSD: bt_open.c,v 1.5 2009/05/07 00:23:45 schmonz Exp $ */
/* NetBSD: bt_open.c,v 1.24 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_open.c,v 1.5 2009/05/07 00:23:45 schmonz Exp $");
/*
* Implementation of btree access method for 4.4BSD.
*
* The design here was originally based on that of the btree access method
* used in the Postgres database system at UC Berkeley. This implementation
* is wholly independent of the Postgres code.
*/
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nbcompat/paths.h>
#include <nbcompat/db.h>
#include "btree.h"
#ifdef DEBUG
#undef MINPSIZE
#define MINPSIZE 128
#endif
static int byteorder(void);
static int nroot(BTREE *);
static int tmp(void);
/*
* __BT_OPEN -- Open a btree.
*
* Creates and fills a DB struct, and calls the routine that actually
* opens the btree.
*
* Parameters:
* fname: filename (NULL for in-memory trees)
* flags: open flag bits
* mode: open permission bits
* b: BTREEINFO pointer
*
* Returns:
* NULL on failure, pointer to DB on success.
*
*/
DB *
__bt_open(const char *fname, int flags, mode_t mode, const BTREEINFO *openinfo,
int dflags)
{
struct stat sb;
BTMETA m;
BTREE *t;
BTREEINFO b;
DB *dbp;
pgno_t ncache;
ssize_t nr;
size_t temp;
int machine_lorder;
t = NULL;
/*
* Intention is to make sure all of the user's selections are okay
* here and then use them without checking. Can't be complete, since
* we don't know the right page size, lorder or flags until the backing
* file is opened. Also, the file's page size can cause the cachesize
* to change.
*/
machine_lorder = byteorder();
if (openinfo) {
b = *openinfo;
/* Flags: R_DUP. */
if (b.flags & ~(R_DUP))
goto einval;
/*
* Page size must be indx_t aligned and >= MINPSIZE. Default
* page size is set farther on, based on the underlying file
* transfer size.
*/
if (b.psize &&
(b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
b.psize & (sizeof(indx_t) - 1)))
goto einval;
/* Minimum number of keys per page; absolute minimum is 2. */
if (b.minkeypage) {
if (b.minkeypage < 2)
goto einval;
} else
b.minkeypage = DEFMINKEYPAGE;
/* If no comparison, use default comparison and prefix. */
if (b.compare == NULL) {
b.compare = __bt_defcmp;
if (b.prefix == NULL)
b.prefix = __bt_defpfx;
}
if (b.lorder == 0)
b.lorder = machine_lorder;
} else {
b.compare = __bt_defcmp;
b.cachesize = 0;
b.flags = 0;
b.lorder = machine_lorder;
b.minkeypage = DEFMINKEYPAGE;
b.prefix = __bt_defpfx;
b.psize = 0;
}
/* Check for the ubiquitous PDP-11. */
if (b.lorder != BIG_ENDIAN && b.lorder != LITTLE_ENDIAN)
goto einval;
/* Allocate and initialize DB and BTREE structures. */
if ((t = (BTREE *)malloc(sizeof(BTREE))) == NULL)
goto err;
memset(t, 0, sizeof(BTREE));
t->bt_fd = -1; /* Don't close unopened fd on error. */
t->bt_lorder = b.lorder;
t->bt_order = NOT;
t->bt_cmp = b.compare;
t->bt_pfx = b.prefix;
t->bt_rfd = -1;
if ((t->bt_dbp = dbp = (DB *)malloc(sizeof(DB))) == NULL)
goto err;
memset(t->bt_dbp, 0, sizeof(DB));
if (t->bt_lorder != machine_lorder)
F_SET(t, B_NEEDSWAP);
dbp->type = DB_BTREE;
dbp->internal = t;
dbp->close = __bt_close;
dbp->del = __bt_delete;
dbp->fd = __bt_fd;
dbp->get = __bt_get;
dbp->put = __bt_put;
dbp->seq = __bt_seq;
dbp->sync = __bt_sync;
/*
* If no file name was supplied, this is an in-memory btree and we
* open a backing temporary file. Otherwise, it's a disk-based tree.
*/
if (fname) {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, B_RDONLY);
break;
case O_RDWR:
break;
case O_WRONLY:
default:
goto einval;
}
if ((t->bt_fd = open(fname, flags, mode)) == -1)
goto err;
if (fcntl(t->bt_fd, F_SETFD, FD_CLOEXEC) == -1)
goto err;
} else {
if ((flags & O_ACCMODE) != O_RDWR)
goto einval;
if ((t->bt_fd = tmp()) == -1)
goto err;
F_SET(t, B_INMEM);
}
if (fcntl(t->bt_fd, F_SETFD, FD_CLOEXEC) == -1)
goto err;
if (fstat(t->bt_fd, &sb))
goto err;
if (sb.st_size) {
if ((nr = read(t->bt_fd, &m, sizeof(BTMETA))) < 0)
goto err;
if (nr != sizeof(BTMETA))
goto eftype;
/*
* Read in the meta-data. This can change the notion of what
* the lorder, page size and flags are, and, when the page size
* changes, the cachesize value can change too. If the user
* specified the wrong byte order for an existing database, we
* don't bother to return an error, we just clear the NEEDSWAP
* bit.
*/
if (m.magic == BTREEMAGIC)
F_CLR(t, B_NEEDSWAP);
else {
F_SET(t, B_NEEDSWAP);
M_32_SWAP(m.magic);
M_32_SWAP(m.version);
M_32_SWAP(m.psize);
M_32_SWAP(m.free);
M_32_SWAP(m.nrecs);
M_32_SWAP(m.flags);
}
if (m.magic != BTREEMAGIC || m.version != BTREEVERSION)
goto eftype;
if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 ||
m.psize & (sizeof(indx_t) - 1))
goto eftype;
if (m.flags & ~SAVEMETA)
goto eftype;
b.psize = m.psize;
F_SET(t, m.flags);
t->bt_free = m.free;
t->bt_nrecs = m.nrecs;
} else {
/*
* Set the page size to the best value for I/O to this file.
* Don't overflow the page offset type.
*/
if (b.psize == 0) {
b.psize = sb.st_blksize;
if (b.psize < MINPSIZE)
b.psize = MINPSIZE;
if (b.psize > MAX_PAGE_OFFSET + 1)
b.psize = MAX_PAGE_OFFSET + 1;
}
/* Set flag if duplicates permitted. */
if (!(b.flags & R_DUP))
F_SET(t, B_NODUPS);
t->bt_free = P_INVALID;
t->bt_nrecs = 0;
F_SET(t, B_METADIRTY);
}
t->bt_psize = b.psize;
/* Set the cache size; must be a multiple of the page size. */
if (b.cachesize && b.cachesize & (b.psize - 1))
b.cachesize += (~b.cachesize & (b.psize - 1)) + 1;
if (b.cachesize < b.psize * MINCACHE)
b.cachesize = b.psize * MINCACHE;
/* Calculate number of pages to cache. */
ncache = (b.cachesize + t->bt_psize - 1) / t->bt_psize;
/*
* The btree data structure requires that at least two keys can fit on
* a page, but other than that there's no fixed requirement. The user
* specified a minimum number per page, and we translated that into the
* number of bytes a key/data pair can use before being placed on an
* overflow page. This calculation includes the page header, the size
* of the index referencing the leaf item and the size of the leaf item
* structure. Also, don't let the user specify a minkeypage such that
* a key/data pair won't fit even if both key and data are on overflow
* pages.
*/
temp = (t->bt_psize - BTDATAOFF) / b.minkeypage -
(sizeof(indx_t) + NBLEAFDBT(0, 0));
_DBFIT(temp, indx_t);
t->bt_ovflsize = (indx_t)temp;
if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
t->bt_ovflsize =
NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
/* Initialize the buffer pool. */
if ((t->bt_mp =
mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
goto err;
if (!F_ISSET(t, B_INMEM))
mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
/* Create a root page if new tree. */
if (nroot(t) == RET_ERROR)
goto err;
/* Global flags. */
if (dflags & DB_LOCK)
F_SET(t, B_DB_LOCK);
if (dflags & DB_SHMEM)
F_SET(t, B_DB_SHMEM);
if (dflags & DB_TXN)
F_SET(t, B_DB_TXN);
return (dbp);
einval: errno = EINVAL;
goto err;
eftype: errno = EFTYPE;
goto err;
err: if (t) {
if (t->bt_dbp)
free(t->bt_dbp);
if (t->bt_fd != -1)
(void)close(t->bt_fd);
free(t);
}
return (NULL);
}
/*
* NROOT -- Create the root of a new tree.
*
* Parameters:
* t: tree
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
nroot(BTREE *t)
{
PAGE *meta, *root;
pgno_t npg;
if ((meta = mpool_get(t->bt_mp, 0, 0)) != NULL) {
mpool_put(t->bt_mp, meta, 0);
return (RET_SUCCESS);
}
if (errno != EINVAL) /* It's OK to not exist. */
return (RET_ERROR);
errno = 0;
if ((meta = mpool_new(t->bt_mp, &npg)) == NULL)
return (RET_ERROR);
if ((root = mpool_new(t->bt_mp, &npg)) == NULL)
return (RET_ERROR);
if (npg != P_ROOT)
return (RET_ERROR);
root->pgno = npg;
root->prevpg = root->nextpg = P_INVALID;
root->lower = BTDATAOFF;
root->upper = t->bt_psize;
root->flags = P_BLEAF;
memset(meta, 0, t->bt_psize);
mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
mpool_put(t->bt_mp, root, MPOOL_DIRTY);
return (RET_SUCCESS);
}
static int
tmp(void)
{
sigset_t set, oset;
size_t len;
int fd;
char *envtmp;
#ifdef PATH_MAX
char path[PATH_MAX];
#else
char path[MAXPATHLEN];
#endif
#if HAVE_ISSETUGID
if (issetugid())
envtmp = NULL;
else
#endif
envtmp = getenv("TMPDIR");
len = snprintf(path,
sizeof(path), "%s/bt.XXXXXX", envtmp ? envtmp : _PATH_TMP);
if (len >= sizeof(path))
return -1;
(void)sigfillset(&set);
(void)sigprocmask(SIG_BLOCK, &set, &oset);
if ((fd = mkstemp(path)) != -1) {
(void)unlink(path);
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
}
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
return(fd);
}
static int
byteorder(void)
{
uint32_t x;
uint8_t *p;
x = 0x01020304;
p = (uint8_t *)(void *)&x;
switch (*p) {
case 1:
return (BIG_ENDIAN);
case 4:
return (LITTLE_ENDIAN);
default:
return (0);
}
}
int
__bt_fd(const DB *dbp)
{
BTREE *t;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* In-memory database can't have a file descriptor. */
if (F_ISSET(t, B_INMEM)) {
errno = ENOENT;
return (-1);
}
return (t->bt_fd);
}

View File

@@ -0,0 +1,230 @@
/* $NetBSD: bt_overflow.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_overflow.c,v 1.16 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_overflow.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/param.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
/*
* Big key/data code.
*
* Big key and data entries are stored on linked lists of pages. The initial
* reference is byte string stored with the key or data and is the page number
* and size. The actual record is stored in a chain of pages linked by the
* nextpg field of the PAGE header.
*
* The first page of the chain has a special property. If the record is used
* by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
* in the header.
*
* XXX
* A single DBT is written to each chain, so a lot of space on the last page
* is wasted. This is a fairly major bug for some data sets.
*/
/*
* __OVFL_GET -- Get an overflow key/data item.
*
* Parameters:
* t: tree
* p: pointer to { pgno_t, uint32_t }
* buf: storage address
* bufsz: storage size
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_get(BTREE *t, void *p, size_t *ssz, void **buf, size_t *bufsz)
{
PAGE *h;
pgno_t pg;
uint32_t sz, nb, plen;
size_t temp;
memmove(&pg, p, sizeof(pgno_t));
memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(uint32_t));
*ssz = sz;
#ifdef DEBUG
if (pg == P_INVALID || sz == 0)
abort();
#endif
/* Make the buffer bigger as necessary. */
if (*bufsz < sz) {
*buf = (char *)(*buf == NULL ? malloc(sz) : realloc(*buf, sz));
if (*buf == NULL)
return (RET_ERROR);
*bufsz = sz;
}
/*
* Step through the linked list of pages, copying the data on each one
* into the buffer. Never copy more than the data's length.
*/
temp = t->bt_psize - BTDATAOFF;
_DBFIT(temp, uint32_t);
plen = (uint32_t)temp;
for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
nb = MIN(sz, plen);
memmove(p, (char *)(void *)h + BTDATAOFF, nb);
mpool_put(t->bt_mp, h, 0);
if ((sz -= nb) == 0)
break;
}
return (RET_SUCCESS);
}
/*
* __OVFL_PUT -- Store an overflow key/data item.
*
* Parameters:
* t: tree
* data: DBT to store
* pgno: storage page number
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_put(BTREE *t, const DBT *dbt, pgno_t *pg)
{
PAGE *h, *last;
void *p;
pgno_t npg;
uint32_t sz, nb, plen;
size_t temp;
/*
* Allocate pages and copy the key/data record into them. Store the
* number of the first page in the chain.
*/
temp = t->bt_psize - BTDATAOFF;
_DBFIT(temp, uint32_t);
plen = (uint32_t)temp;
last = NULL;
p = dbt->data;
temp = dbt->size;
_DBFIT(temp, uint32_t);
sz = temp;
for (;; p = (char *)p + plen, last = h) {
if ((h = __bt_new(t, &npg)) == NULL)
return (RET_ERROR);
h->pgno = npg;
h->nextpg = h->prevpg = P_INVALID;
h->flags = P_OVERFLOW;
h->lower = h->upper = 0;
nb = MIN(sz, plen);
(void)memmove((char *)(void *)h + BTDATAOFF, p, (size_t)nb);
if (last) {
last->nextpg = h->pgno;
mpool_put(t->bt_mp, last, MPOOL_DIRTY);
} else
*pg = h->pgno;
if ((sz -= nb) == 0) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
}
}
return (RET_SUCCESS);
}
/*
* __OVFL_DELETE -- Delete an overflow chain.
*
* Parameters:
* t: tree
* p: pointer to { pgno_t, uint32_t }
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_delete(BTREE *t, void *p)
{
PAGE *h;
pgno_t pg;
uint32_t sz, plen;
size_t temp;
(void)memmove(&pg, p, sizeof(pgno_t));
(void)memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(uint32_t));
#ifdef DEBUG
if (pg == P_INVALID || sz == 0)
abort();
#endif
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Don't delete chains used by internal pages. */
if (h->flags & P_PRESERVE) {
mpool_put(t->bt_mp, h, 0);
return (RET_SUCCESS);
}
/* Step through the chain, calling the free routine for each page. */
temp = t->bt_psize - BTDATAOFF;
_DBFIT(temp, uint32_t);
plen = (uint32_t)temp;
for (;; sz -= plen) {
pg = h->nextpg;
__bt_free(t, h);
if (sz <= plen)
break;
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
}
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,97 @@
/* $NetBSD: bt_page.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_page.c,v 1.13 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_page.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <nbcompat/db.h>
#include "btree.h"
/*
* __bt_free --
* Put a page on the freelist.
*
* Parameters:
* t: tree
* h: page to free
*
* Returns:
* RET_ERROR, RET_SUCCESS
*
* Side-effect:
* mpool_put's the page.
*/
int
__bt_free(BTREE *t, PAGE *h)
{
/* Insert the page at the head of the free list. */
h->prevpg = P_INVALID;
h->nextpg = t->bt_free;
t->bt_free = h->pgno;
F_SET(t, B_METADIRTY);
/* Make sure the page gets written back. */
return (mpool_put(t->bt_mp, h, MPOOL_DIRTY));
}
/*
* __bt_new --
* Get a new page, preferably from the freelist.
*
* Parameters:
* t: tree
* npg: storage for page number.
*
* Returns:
* Pointer to a page, NULL on error.
*/
PAGE *
__bt_new(BTREE *t, pgno_t *npg)
{
PAGE *h;
if (t->bt_free != P_INVALID &&
(h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) {
*npg = t->bt_free;
t->bt_free = h->nextpg;
F_SET(t, B_METADIRTY);
return (h);
}
return (mpool_new(t->bt_mp, npg));
}

View File

@@ -0,0 +1,317 @@
/* $NetBSD: bt_put.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_put.c,v 1.18 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_put.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
static EPG *bt_fast(BTREE *, const DBT *, const DBT *, int *);
/*
* __BT_PUT -- Add a btree item to the tree.
*
* Parameters:
* dbp: pointer to access method
* key: key
* data: data
* flag: R_NOOVERWRITE
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
* tree and R_NOOVERWRITE specified.
*/
int
__bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
{
BTREE *t;
DBT tkey, tdata;
EPG *e = NULL; /* pacify gcc */
PAGE *h;
indx_t idx, nxtindex;
pgno_t pg;
uint32_t nbytes, temp;
int dflags, exact, status;
char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Check for change to a read-only tree. */
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
case R_NOOVERWRITE:
break;
case R_CURSOR:
/*
* If flags is R_CURSOR, put the cursor. Must already
* have started a scan and not have already deleted it.
*/
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor,
CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
break;
/* FALLTHROUGH */
default:
errno = EINVAL;
return (RET_ERROR);
}
/*
* If the key/data pair won't fit on a page, store it on overflow
* pages. Only put the key on the overflow page if the pair are
* still too big after moving the data to an overflow page.
*
* XXX
* If the insert fails later on, the overflow pages aren't recovered.
*/
dflags = 0;
if (key->size + data->size > t->bt_ovflsize) {
if (key->size > t->bt_ovflsize) {
storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
return (RET_ERROR);
tkey.data = kb;
tkey.size = NOVFLSIZE;
memmove(kb, &pg, sizeof(pgno_t));
memmove(kb + sizeof(pgno_t),
&key->size, sizeof(uint32_t));
dflags |= P_BIGKEY;
key = &tkey;
}
if (key->size + data->size > t->bt_ovflsize) {
if (__ovfl_put(t, data, &pg) == RET_ERROR)
return (RET_ERROR);
tdata.data = db;
tdata.size = NOVFLSIZE;
memmove(db, &pg, sizeof(pgno_t));
_DBFIT(data->size, uint32_t);
temp = (uint32_t)data->size;
(void)memmove(db + sizeof(pgno_t),
&temp, sizeof(uint32_t));
dflags |= P_BIGDATA;
data = &tdata;
}
if (key->size + data->size > t->bt_ovflsize)
goto storekey;
}
/* Replace the cursor. */
if (flags == R_CURSOR) {
if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
return (RET_ERROR);
idx = t->bt_cursor.pg.index;
goto delete;
}
/*
* Find the key to delete, or, the location at which to insert.
* Bt_fast and __bt_search both pin the returned page.
*/
if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
if ((e = __bt_search(t, key, &exact)) == NULL)
return (RET_ERROR);
h = e->page;
idx = e->index;
/*
* Add the key/data pair to the tree. If an identical key is already
* in the tree, and R_NOOVERWRITE is set, an error is returned. If
* R_NOOVERWRITE is not set, the key is either added (if duplicates are
* permitted) or an error is returned.
*/
switch (flags) {
case R_NOOVERWRITE:
if (!exact)
break;
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
default:
if (!exact || !F_ISSET(t, B_NODUPS))
break;
/*
* !!!
* Note, the delete may empty the page, so we need to put a
* new entry into the page immediately.
*/
delete: if (__bt_dleaf(t, key, h, (u_int)idx) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
break;
}
/*
* If not enough room, or the user has put a ceiling on the number of
* keys permitted in the page, split the page. The split code will
* insert the key and data and unpin the current page. If inserting
* into the offset array, shift the pointers up.
*/
nbytes = NBLEAFDBT(key->size, data->size);
if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
if ((status = __bt_split(t, h, key,
data, dflags, nbytes, (u_int)idx)) != RET_SUCCESS)
return (status);
goto success;
}
if (idx < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + idx + 1, h->linp + idx,
(nxtindex - idx) * sizeof(indx_t));
h->lower += sizeof(indx_t);
h->linp[idx] = h->upper -= nbytes;
dest = (char *)(void *)h + h->upper;
WR_BLEAF(dest, key, data, dflags);
/* If the cursor is on this page, adjust it as necessary. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
++t->bt_cursor.pg.index;
if (t->bt_order == NOT) {
if (h->nextpg == P_INVALID) {
if (idx == NEXTINDEX(h) - 1) {
t->bt_order = FORWARD;
t->bt_last.index = idx;
t->bt_last.pgno = h->pgno;
}
} else if (h->prevpg == P_INVALID) {
if (idx == 0) {
t->bt_order = BACK;
t->bt_last.index = 0;
t->bt_last.pgno = h->pgno;
}
}
}
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
success:
if (flags == R_SETCURSOR)
__bt_setcur(t, e->page->pgno, (u_int)e->index);
F_SET(t, B_MODIFIED);
return (RET_SUCCESS);
}
#ifdef STATISTICS
unsigned long bt_cache_hit, bt_cache_miss;
#endif
/*
* BT_FAST -- Do a quick check for sorted data.
*
* Parameters:
* t: tree
* key: key to insert
*
* Returns:
* EPG for new record or NULL if not found.
*/
static EPG *
bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
{
PAGE *h;
uint32_t nbytes;
int cmp;
if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
t->bt_order = NOT;
return (NULL);
}
t->bt_cur.page = h;
t->bt_cur.index = t->bt_last.index;
/*
* If won't fit in this page or have too many keys in this page,
* have to search to get split stack.
*/
nbytes = NBLEAFDBT(key->size, data->size);
if (h->upper - h->lower < nbytes + sizeof(indx_t))
goto miss;
if (t->bt_order == FORWARD) {
if (t->bt_cur.page->nextpg != P_INVALID)
goto miss;
if (t->bt_cur.index != NEXTINDEX(h) - 1)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
goto miss;
t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
} else {
if (t->bt_cur.page->prevpg != P_INVALID)
goto miss;
if (t->bt_cur.index != 0)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
goto miss;
t->bt_last.index = 0;
}
*exactp = cmp == 0;
#ifdef STATISTICS
++bt_cache_hit;
#endif
return (&t->bt_cur);
miss:
#ifdef STATISTICS
++bt_cache_miss;
#endif
t->bt_order = NOT;
mpool_put(t->bt_mp, h, 0);
return (NULL);
}

View File

@@ -0,0 +1,203 @@
/* $NetBSD: bt_search.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_search.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_search.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <nbcompat/db.h>
#include "btree.h"
static int __bt_snext(BTREE *, PAGE *, const DBT *, int *);
static int __bt_sprev(BTREE *, PAGE *, const DBT *, int *);
/*
* __bt_search --
* Search a btree for a key.
*
* Parameters:
* t: tree to search
* key: key to find
* exactp: pointer to exact match flag
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__bt_search(BTREE *t, const DBT *key, int *exactp)
{
PAGE *h;
indx_t base, idx, lim;
pgno_t pg;
int cmp;
BT_CLR(t);
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (NULL);
/* Do a binary search on the current page. */
t->bt_cur.page = h;
for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
t->bt_cur.index = idx = base + ((uint32_t)lim >> 1);
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
if (h->flags & P_BLEAF) {
*exactp = 1;
return (&t->bt_cur);
}
goto next;
}
if (cmp > 0) {
base = idx + 1;
--lim;
}
}
/*
* If it's a leaf page, we're almost done. If no duplicates
* are allowed, or we have an exact match, we're done. Else,
* it's possible that there were matching keys on this page,
* which later deleted, and we're on a page with no matches
* while there are matches on other pages. If at the start or
* end of a page, check the adjacent page.
*/
if (h->flags & P_BLEAF) {
if (!F_ISSET(t, B_NODUPS)) {
if (base == 0 &&
h->prevpg != P_INVALID &&
__bt_sprev(t, h, key, exactp))
return (&t->bt_cur);
if (base == NEXTINDEX(h) &&
h->nextpg != P_INVALID &&
__bt_snext(t, h, key, exactp))
return (&t->bt_cur);
}
*exactp = 0;
t->bt_cur.index = base;
return (&t->bt_cur);
}
/*
* No match found. Base is the smallest index greater than
* key and may be zero or a last + 1 index. If it's non-zero,
* decrement by one, and record the internal page which should
* be a parent page for the key. If a split later occurs, the
* inserted page will be to the right of the saved page.
*/
idx = base ? base - 1 : base;
next: BT_PUSH(t, h->pgno, idx);
pg = GETBINTERNAL(h, idx)->pgno;
mpool_put(t->bt_mp, h, 0);
}
}
/*
* __bt_snext --
* Check for an exact match after the key.
*
* Parameters:
* t: tree
* h: current page
* key: key
* exactp: pointer to exact match flag
*
* Returns:
* If an exact match found.
*/
static int
__bt_snext(BTREE *t, PAGE *h, const DBT *key, int *exactp)
{
EPG e;
/*
* Get the next page. The key is either an exact
* match, or not as good as the one we already have.
*/
if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (0);
e.index = 0;
if (__bt_cmp(t, key, &e) == 0) {
mpool_put(t->bt_mp, h, 0);
t->bt_cur = e;
*exactp = 1;
return (1);
}
mpool_put(t->bt_mp, e.page, 0);
return (0);
}
/*
* __bt_sprev --
* Check for an exact match before the key.
*
* Parameters:
* t: tree
* h: current page
* key: key
* exactp: pointer to exact match flag
*
* Returns:
* If an exact match found.
*/
static int
__bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
{
EPG e;
/*
* Get the previous page. The key is either an exact
* match, or not as good as the one we already have.
*/
if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (0);
e.index = NEXTINDEX(e.page) - 1;
if (__bt_cmp(t, key, &e) == 0) {
mpool_put(t->bt_mp, h, 0);
t->bt_cur = e;
*exactp = 1;
return (1);
}
mpool_put(t->bt_mp, e.page, 0);
return (0);
}

View File

@@ -0,0 +1,440 @@
/* $NetBSD: bt_seq.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_seq.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_seq.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <nbcompat/db.h>
#include "btree.h"
static int __bt_first(BTREE *, const DBT *, EPG *, int *);
static int __bt_seqadv(BTREE *, EPG *, int);
static int __bt_seqset(BTREE *, EPG *, DBT *, int);
/*
* Sequential scan support.
*
* The tree can be scanned sequentially, starting from either end of the
* tree or from any specific key. A scan request before any scanning is
* done is initialized as starting from the least node.
*/
/*
* __bt_seq --
* Btree sequential scan interface.
*
* Parameters:
* dbp: pointer to access method
* key: key for positioning and return value
* data: data return value
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
int
__bt_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG e;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/*
* If scan unitialized as yet, or starting at a specific record, set
* the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
* the page the cursor references if they're successful.
*/
switch (flags) {
case R_NEXT:
case R_PREV:
if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
status = __bt_seqadv(t, &e, (int)flags);
break;
}
/* FALLTHROUGH */
case R_FIRST:
case R_LAST:
case R_CURSOR:
status = __bt_seqset(t, &e, key, (int)flags);
break;
default:
errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS) {
__bt_setcur(t, e.page->pgno, (u_int)e.index);
status =
__bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
/*
* If the user is doing concurrent access, we copied the
* key/data, toss the page.
*/
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e.page, 0);
else
t->bt_pinned = e.page;
}
return (status);
}
/*
* __bt_seqset --
* Set the sequential scan to a specific key.
*
* Parameters:
* t: tree
* ep: storage for returned key
* key: key for initial scan position
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
*
* Side effects:
* Pins the page the cursor references.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags)
{
PAGE *h;
pgno_t pg;
int exact;
/*
* Find the first, last or specific key in the tree and point the
* cursor at it. The cursor may not be moved until a new key has
* been found.
*/
switch (flags) {
case R_CURSOR: /* Keyed scan. */
/*
* Find the first instance of the key or the smallest key
* which is greater than or equal to the specified key.
*/
if (key->data == NULL || key->size == 0) {
errno = EINVAL;
return (RET_ERROR);
}
return (__bt_first(t, key, ep, &exact));
case R_FIRST: /* First record. */
case R_NEXT:
/* Walk down the left-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, 0)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = 0;
break;
case R_LAST: /* Last record. */
case R_PREV:
/* Walk down the right-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = NEXTINDEX(h) - 1;
break;
}
return (RET_SUCCESS);
}
/*
* __bt_seqadvance --
* Advance the sequential scan.
*
* Parameters:
* t: tree
* flags: R_NEXT, R_PREV
*
* Side effects:
* Pins the page the new key/data record is on.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqadv(BTREE *t, EPG *ep, int flags)
{
CURSOR *c;
PAGE *h;
indx_t idx = 0; /* pacify gcc */
pgno_t pg;
int exact;
/*
* There are a couple of states that we can be in. The cursor has
* been initialized by the time we get here, but that's all we know.
*/
c = &t->bt_cursor;
/*
* The cursor was deleted where there weren't any duplicate records,
* so the key was saved. Find out where that key would go in the
* current tree. It doesn't matter if the returned key is an exact
* match or not -- if it's an exact match, the record was added after
* the delete so we can just return it. If not, as long as there's
* a record there, return it.
*/
if (F_ISSET(c, CURS_ACQUIRE))
return (__bt_first(t, &c->key, ep, &exact));
/* Get the page referenced by the cursor. */
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* Find the next/previous record in the tree and point the cursor at
* it. The cursor may not be moved until a new key has been found.
*/
switch (flags) {
case R_NEXT: /* Next record. */
/*
* The cursor was deleted in duplicate records, and moved
* forward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_AFTER))
goto usecurrent;
idx = c->pg.index;
if (++idx == NEXTINDEX(h)) {
pg = h->nextpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = 0;
}
break;
case R_PREV: /* Previous record. */
/*
* The cursor was deleted in duplicate records, and moved
* backward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_BEFORE)) {
usecurrent: F_CLR(c, CURS_AFTER | CURS_BEFORE);
ep->page = h;
ep->index = c->pg.index;
return (RET_SUCCESS);
}
idx = c->pg.index;
if (idx == 0) {
pg = h->prevpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = NEXTINDEX(h) - 1;
} else
--idx;
break;
}
ep->page = h;
ep->index = idx;
return (RET_SUCCESS);
}
/*
* __bt_first --
* Find the first entry.
*
* Parameters:
* t: the tree
* key: the key
* erval: return EPG
* exactp: pointer to exact match flag
*
* Returns:
* The first entry in the tree greater than or equal to key,
* or RET_SPECIAL if no such key exists.
*/
static int
__bt_first(BTREE *t, const DBT *key, EPG *erval, int *exactp)
{
PAGE *h;
EPG *ep, save;
pgno_t pg;
/*
* Find any matching record; __bt_search pins the page.
*
* If it's an exact match and duplicates are possible, walk backwards
* in the tree until we find the first one. Otherwise, make sure it's
* a valid key (__bt_search may return an index just past the end of a
* page) and return it.
*/
if ((ep = __bt_search(t, key, exactp)) == NULL)
return (0);
if (*exactp) {
if (F_ISSET(t, B_NODUPS)) {
*erval = *ep;
return (RET_SUCCESS);
}
/*
* Walk backwards, as long as the entry matches and there are
* keys left in the tree. Save a copy of each match in case
* we go too far.
*/
save = *ep;
h = ep->page;
do {
if (save.page->pgno != ep->page->pgno) {
mpool_put(t->bt_mp, save.page, 0);
save = *ep;
} else
save.index = ep->index;
/*
* Don't unpin the page the last (or original) match
* was on, but make sure it's unpinned if an error
* occurs.
*/
if (ep->index == 0) {
if (h->prevpg == P_INVALID)
break;
if (h->pgno != save.page->pgno)
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp,
h->prevpg, 0)) == NULL)
return (RET_ERROR);
ep->page = h;
ep->index = NEXTINDEX(h);
}
--ep->index;
} while (__bt_cmp(t, key, ep) == 0);
/*
* Reach here with the last page that was looked at pinned,
* which may or may not be the same as the last (or original)
* match page. If it's not useful, release it.
*/
if (h->pgno != save.page->pgno)
mpool_put(t->bt_mp, h, 0);
*erval = save;
return (RET_SUCCESS);
}
/* If at the end of a page, find the next entry. */
if (ep->index == NEXTINDEX(ep->page)) {
h = ep->page;
pg = h->nextpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
ep->index = 0;
ep->page = h;
}
*erval = *ep;
return (RET_SUCCESS);
}
/*
* __bt_setcur --
* Set the cursor to an entry in the tree.
*
* Parameters:
* t: the tree
* pgno: page number
* idx: page index
*/
void
__bt_setcur(BTREE *t, pgno_t pgno, u_int idx)
{
/* Lose any already deleted key. */
if (t->bt_cursor.key.data != NULL) {
free(t->bt_cursor.key.data);
t->bt_cursor.key.size = 0;
t->bt_cursor.key.data = NULL;
}
F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
/* Update the cursor. */
t->bt_cursor.pg.pgno = pgno;
t->bt_cursor.pg.index = idx;
F_SET(&t->bt_cursor, CURS_INIT);
}

View File

@@ -0,0 +1,825 @@
/* $NetBSD: bt_split.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_split.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_split.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
static int bt_broot(BTREE *, PAGE *, PAGE *, PAGE *);
static PAGE *bt_page(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
static int bt_preserve(BTREE *, pgno_t);
static PAGE *bt_psplit(BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t);
static PAGE *bt_root(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
static int bt_rroot(BTREE *, PAGE *, PAGE *, PAGE *);
static recno_t rec_total(PAGE *);
#ifdef STATISTICS
unsigned long bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
#endif
/*
* __BT_SPLIT -- Split the tree.
*
* Parameters:
* t: tree
* sp: page to split
* key: key to insert
* data: data to insert
* flags: BIGKEY/BIGDATA flags
* ilen: insert length
* skip: index to leave open
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__bt_split(BTREE *t, PAGE *sp, const DBT *key, const DBT *data, int flags,
size_t ilen, uint32_t argskip)
{
BINTERNAL *bi = NULL; /* pacify gcc */
BLEAF *bl = NULL, *tbl; /* pacify gcc */
DBT a, b;
EPGNO *parent;
PAGE *h, *l, *r, *lchild, *rchild;
indx_t nxtindex;
uint16_t skip;
uint32_t n, nbytes, nksize = 0; /* pacify gcc */
int parentsplit;
char *dest;
/*
* Split the page into two pages, l and r. The split routines return
* a pointer to the page into which the key should be inserted and with
* skip set to the offset which should be used. Additionally, l and r
* are pinned.
*/
skip = argskip;
h = sp->pgno == P_ROOT ?
bt_root(t, sp, &l, &r, &skip, ilen) :
bt_page(t, sp, &l, &r, &skip, ilen);
if (h == NULL)
return (RET_ERROR);
/*
* Insert the new key/data pair into the leaf page. (Key inserts
* always cause a leaf page to split first.)
*/
_DBFIT(ilen, indx_t);
h->upper -= (indx_t)ilen;
h->linp[skip] = h->upper;
dest = (char *)(void *)h + h->upper;
if (F_ISSET(t, R_RECNO))
WR_RLEAF(dest, data, flags);
else
WR_BLEAF(dest, key, data, flags);
/* If the root page was split, make it look right. */
if (sp->pgno == P_ROOT &&
(F_ISSET(t, R_RECNO) ?
bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
goto err2;
/*
* Now we walk the parent page stack -- a LIFO stack of the pages that
* were traversed when we searched for the page that split. Each stack
* entry is a page number and a page index offset. The offset is for
* the page traversed on the search. We've just split a page, so we
* have to insert a new key into the parent page.
*
* If the insert into the parent page causes it to split, may have to
* continue splitting all the way up the tree. We stop if the root
* splits or the page inserted into didn't have to split to hold the
* new key. Some algorithms replace the key for the old page as well
* as the new page. We don't, as there's no reason to believe that the
* first key on the old page is any better than the key we have, and,
* in the case of a key being placed at index 0 causing the split, the
* key is unavailable.
*
* There are a maximum of 5 pages pinned at any time. We keep the left
* and right pages pinned while working on the parent. The 5 are the
* two children, left parent and right parent (when the parent splits)
* and the root page or the overflow key page when calling bt_preserve.
* This code must make sure that all pins are released other than the
* root page or overflow page which is unlocked elsewhere.
*/
while ((parent = BT_POP(t)) != NULL) {
lchild = l;
rchild = r;
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
goto err2;
/*
* The new key goes ONE AFTER the index, because the split
* was to the right.
*/
skip = parent->index + 1;
/*
* Calculate the space needed on the parent page.
*
* Prefix trees: space hack when inserting into BINTERNAL
* pages. Retain only what's needed to distinguish between
* the new entry and the LAST entry on the page to its left.
* If the keys compare equal, retain the entire key. Note,
* we don't touch overflow keys, and the entire key must be
* retained for the next-to-left most key on the leftmost
* page of each level, or the search will fail. Applicable
* ONLY to internal pages that have leaf pages as children.
* Further reduction of the key between pairs of internal
* pages loses too much information.
*/
switch (rchild->flags & P_TYPE) {
case P_BINTERNAL:
bi = GETBINTERNAL(rchild, 0);
nbytes = NBINTERNAL(bi->ksize);
break;
case P_BLEAF:
bl = GETBLEAF(rchild, 0);
nbytes = NBINTERNAL(bl->ksize);
if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
(h->prevpg != P_INVALID || skip > 1)) {
size_t temp;
tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
a.size = tbl->ksize;
a.data = tbl->bytes;
b.size = bl->ksize;
b.data = bl->bytes;
temp = t->bt_pfx(&a, &b);
_DBFIT(temp, uint32_t);
nksize = (uint32_t)temp;
n = NBINTERNAL(nksize);
if (n < nbytes) {
#ifdef STATISTICS
bt_pfxsaved += nbytes - n;
#endif
nbytes = n;
} else
nksize = 0;
} else
nksize = 0;
break;
case P_RINTERNAL:
case P_RLEAF:
nbytes = NRINTERNAL;
break;
default:
abort();
}
/* Split the parent page if necessary or shift the indices. */
if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
sp = h;
h = h->pgno == P_ROOT ?
bt_root(t, h, &l, &r, &skip, nbytes) :
bt_page(t, h, &l, &r, &skip, nbytes);
if (h == NULL)
goto err1;
parentsplit = 1;
} else {
if (skip < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + skip + 1, h->linp + skip,
(nxtindex - skip) * sizeof(indx_t));
h->lower += sizeof(indx_t);
parentsplit = 0;
}
/* Insert the key into the parent page. */
switch (rchild->flags & P_TYPE) {
case P_BINTERNAL:
h->linp[skip] = h->upper -= nbytes;
dest = (char *)(void *)h + h->linp[skip];
memmove(dest, bi, nbytes);
((BINTERNAL *)(void *)dest)->pgno = rchild->pgno;
break;
case P_BLEAF:
h->linp[skip] = h->upper -= nbytes;
dest = (char *)(void *)h + h->linp[skip];
WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
rchild->pgno, bl->flags & P_BIGKEY);
memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
if (bl->flags & P_BIGKEY &&
bt_preserve(t, *(pgno_t *)(void *)bl->bytes) ==
RET_ERROR)
goto err1;
break;
case P_RINTERNAL:
/*
* Update the left page count. If split
* added at index 0, fix the correct page.
*/
if (skip > 0)
dest = (char *)(void *)h + h->linp[skip - 1];
else
dest = (char *)(void *)l + l->linp[NEXTINDEX(l) - 1];
((RINTERNAL *)(void *)dest)->nrecs = rec_total(lchild);
((RINTERNAL *)(void *)dest)->pgno = lchild->pgno;
/* Update the right page count. */
h->linp[skip] = h->upper -= nbytes;
dest = (char *)(void *)h + h->linp[skip];
((RINTERNAL *)(void *)dest)->nrecs = rec_total(rchild);
((RINTERNAL *)(void *)dest)->pgno = rchild->pgno;
break;
case P_RLEAF:
/*
* Update the left page count. If split
* added at index 0, fix the correct page.
*/
if (skip > 0)
dest = (char *)(void *)h + h->linp[skip - 1];
else
dest = (char *)(void *)l + l->linp[NEXTINDEX(l) - 1];
((RINTERNAL *)(void *)dest)->nrecs = NEXTINDEX(lchild);
((RINTERNAL *)(void *)dest)->pgno = lchild->pgno;
/* Update the right page count. */
h->linp[skip] = h->upper -= nbytes;
dest = (char *)(void *)h + h->linp[skip];
((RINTERNAL *)(void *)dest)->nrecs = NEXTINDEX(rchild);
((RINTERNAL *)(void *)dest)->pgno = rchild->pgno;
break;
default:
abort();
}
/* Unpin the held pages. */
if (!parentsplit) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
}
/* If the root page was split, make it look right. */
if (sp->pgno == P_ROOT &&
(F_ISSET(t, R_RECNO) ?
bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
goto err1;
mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
}
/* Unpin the held pages. */
mpool_put(t->bt_mp, l, MPOOL_DIRTY);
mpool_put(t->bt_mp, r, MPOOL_DIRTY);
/* Clear any pages left on the stack. */
return (RET_SUCCESS);
/*
* If something fails in the above loop we were already walking back
* up the tree and the tree is now inconsistent. Nothing much we can
* do about it but release any memory we're holding.
*/
err1: mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
err2: mpool_put(t->bt_mp, l, 0);
mpool_put(t->bt_mp, r, 0);
__dbpanic(t->bt_dbp);
return (RET_ERROR);
}
/*
* BT_PAGE -- Split a non-root page of a btree.
*
* Parameters:
* t: tree
* h: root page
* lp: pointer to left page pointer
* rp: pointer to right page pointer
* skip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert or NULL on error.
*/
static PAGE *
bt_page(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
{
PAGE *l, *r, *tp;
pgno_t npg;
#ifdef STATISTICS
++bt_split;
#endif
/* Put the new right page for the split into place. */
if ((r = __bt_new(t, &npg)) == NULL)
return (NULL);
r->pgno = npg;
r->lower = BTDATAOFF;
r->upper = t->bt_psize;
r->nextpg = h->nextpg;
r->prevpg = h->pgno;
r->flags = h->flags & P_TYPE;
/*
* If we're splitting the last page on a level because we're appending
* a key to it (skip is NEXTINDEX()), it's likely that the data is
* sorted. Adding an empty page on the side of the level is less work
* and can push the fill factor much higher than normal. If we're
* wrong it's no big deal, we'll just do the split the right way next
* time. It may look like it's equally easy to do a similar hack for
* reverse sorted data, that is, split the tree left, but it's not.
* Don't even try.
*/
if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
#ifdef STATISTICS
++bt_sortsplit;
#endif
h->nextpg = r->pgno;
r->lower = BTDATAOFF + sizeof(indx_t);
*skip = 0;
*lp = h;
*rp = r;
return (r);
}
/* Put the new left page for the split into place. */
if ((l = (PAGE *)malloc(t->bt_psize)) == NULL) {
mpool_put(t->bt_mp, r, 0);
return (NULL);
}
#ifdef PURIFY
memset(l, 0xff, t->bt_psize);
#endif
l->pgno = h->pgno;
l->nextpg = r->pgno;
l->prevpg = h->prevpg;
l->lower = BTDATAOFF;
l->upper = t->bt_psize;
l->flags = h->flags & P_TYPE;
/* Fix up the previous pointer of the page after the split page. */
if (h->nextpg != P_INVALID) {
if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
free(l);
/* XXX mpool_free(t->bt_mp, r->pgno); */
return (NULL);
}
tp->prevpg = r->pgno;
mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
}
/*
* Split right. The key/data pairs aren't sorted in the btree page so
* it's simpler to copy the data from the split page onto two new pages
* instead of copying half the data to the right page and compacting
* the left page in place. Since the left page can't change, we have
* to swap the original and the allocated left page after the split.
*/
tp = bt_psplit(t, h, l, r, skip, ilen);
/* Move the new left page onto the old left page. */
memmove(h, l, t->bt_psize);
if (tp == l)
tp = h;
free(l);
*lp = h;
*rp = r;
return (tp);
}
/*
* BT_ROOT -- Split the root page of a btree.
*
* Parameters:
* t: tree
* h: root page
* lp: pointer to left page pointer
* rp: pointer to right page pointer
* skip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert or NULL on error.
*/
static PAGE *
bt_root(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
{
PAGE *l, *r, *tp;
pgno_t lnpg, rnpg;
#ifdef STATISTICS
++bt_split;
++bt_rootsplit;
#endif
/* Put the new left and right pages for the split into place. */
if ((l = __bt_new(t, &lnpg)) == NULL ||
(r = __bt_new(t, &rnpg)) == NULL)
return (NULL);
l->pgno = lnpg;
r->pgno = rnpg;
l->nextpg = r->pgno;
r->prevpg = l->pgno;
l->prevpg = r->nextpg = P_INVALID;
l->lower = r->lower = BTDATAOFF;
l->upper = r->upper = t->bt_psize;
l->flags = r->flags = h->flags & P_TYPE;
/* Split the root page. */
tp = bt_psplit(t, h, l, r, skip, ilen);
*lp = l;
*rp = r;
return (tp);
}
/*
* BT_RROOT -- Fix up the recno root page after it has been split.
*
* Parameters:
* t: tree
* h: root page
* l: left page
* r: right page
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_rroot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
{
char *dest;
uint32_t sz;
size_t temp;
temp = t->bt_psize - NRINTERNAL;
_DBFIT(temp, uint32_t);
sz = (uint32_t)temp;
/* Insert the left and right keys, set the header information. */
_DBFIT(sz, indx_t);
h->linp[0] = h->upper = (indx_t)sz;
dest = (char *)(void *)h + h->upper;
WR_RINTERNAL(dest,
l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
h->linp[1] = h->upper -= NRINTERNAL;
dest = (char *)(void *)h + h->upper;
WR_RINTERNAL(dest,
r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
h->lower = BTDATAOFF + 2 * sizeof(indx_t);
/* Unpin the root page, set to recno internal page. */
h->flags &= ~P_TYPE;
h->flags |= P_RINTERNAL;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* BT_BROOT -- Fix up the btree root page after it has been split.
*
* Parameters:
* t: tree
* h: root page
* l: left page
* r: right page
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_broot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
{
BINTERNAL *bi = NULL; /* pacify gcc */
BLEAF *bl;
uint32_t nbytes;
char *dest;
/*
* If the root page was a leaf page, change it into an internal page.
* We copy the key we split on (but not the key's data, in the case of
* a leaf page) to the new root page.
*
* The btree comparison code guarantees that the left-most key on any
* level of the tree is never used, so it doesn't need to be filled in.
*/
nbytes = NBINTERNAL(0);
h->linp[0] = h->upper = t->bt_psize - nbytes;
dest = (char *)(void *)h + h->upper;
WR_BINTERNAL(dest, 0, l->pgno, 0);
switch (h->flags & P_TYPE) {
case P_BLEAF:
bl = GETBLEAF(r, 0);
nbytes = NBINTERNAL(bl->ksize);
h->linp[1] = h->upper -= nbytes;
dest = (char *)(void *)h + h->upper;
WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
memmove(dest, bl->bytes, bl->ksize);
/*
* If the key is on an overflow page, mark the overflow chain
* so it isn't deleted when the leaf copy of the key is deleted.
*/
if (bl->flags & P_BIGKEY &&
bt_preserve(t, *(pgno_t *)(void *)bl->bytes) == RET_ERROR)
return (RET_ERROR);
break;
case P_BINTERNAL:
bi = GETBINTERNAL(r, 0);
nbytes = NBINTERNAL(bi->ksize);
h->linp[1] = h->upper -= nbytes;
dest = (char *)(void *)h + h->upper;
memmove(dest, bi, nbytes);
((BINTERNAL *)(void *)dest)->pgno = r->pgno;
break;
default:
abort();
}
/* There are two keys on the page. */
h->lower = BTDATAOFF + 2 * sizeof(indx_t);
/* Unpin the root page, set to btree internal page. */
h->flags &= ~P_TYPE;
h->flags |= P_BINTERNAL;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* BT_PSPLIT -- Do the real work of splitting the page.
*
* Parameters:
* t: tree
* h: page to be split
* l: page to put lower half of data
* r: page to put upper half of data
* pskip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert.
*/
static PAGE *
bt_psplit(BTREE *t, PAGE *h, PAGE *l, PAGE *r, indx_t *pskip, size_t ilen)
{
BINTERNAL *bi;
BLEAF *bl;
CURSOR *c;
RLEAF *rl;
PAGE *rval;
void *src = NULL; /* pacify gcc */
indx_t full, half, nxt, off, skip, top, used;
uint32_t nbytes;
size_t temp;
int bigkeycnt, isbigkey;
/*
* Split the data to the left and right pages. Leave the skip index
* open. Additionally, make some effort not to split on an overflow
* key. This makes internal page processing faster and can save
* space as overflow keys used by internal pages are never deleted.
*/
bigkeycnt = 0;
skip = *pskip;
temp = t->bt_psize - BTDATAOFF;
_DBFIT(temp, indx_t);
full = (indx_t)temp;
half = full / 2;
used = 0;
for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
if (skip == off) {
_DBFIT(ilen, uint32_t);
nbytes = (uint32_t)ilen;
isbigkey = 0; /* XXX: not really known. */
} else
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
src = bi = GETBINTERNAL(h, nxt);
nbytes = NBINTERNAL(bi->ksize);
isbigkey = bi->flags & P_BIGKEY;
break;
case P_BLEAF:
src = bl = GETBLEAF(h, nxt);
nbytes = NBLEAF(bl);
isbigkey = bl->flags & P_BIGKEY;
break;
case P_RINTERNAL:
src = GETRINTERNAL(h, nxt);
nbytes = NRINTERNAL;
isbigkey = 0;
break;
case P_RLEAF:
src = rl = GETRLEAF(h, nxt);
nbytes = NRLEAF(rl);
isbigkey = 0;
break;
default:
abort();
}
/*
* If the key/data pairs are substantial fractions of the max
* possible size for the page, it's possible to get situations
* where we decide to try and copy too much onto the left page.
* Make sure that doesn't happen.
*/
if ((skip <= off && used + nbytes + sizeof(indx_t) >= full) ||
nxt == top - 1) {
--off;
break;
}
/* Copy the key/data pair, if not the skipped index. */
if (skip != off) {
++nxt;
l->linp[off] = l->upper -= nbytes;
memmove((char *)(void *)l + l->upper, src, nbytes);
}
temp = nbytes + sizeof(indx_t);
_DBFIT(temp, indx_t);
used += (indx_t)temp;
if (used >= half) {
if (!isbigkey || bigkeycnt == 3)
break;
else
++bigkeycnt;
}
}
/*
* Off is the last offset that's valid for the left page.
* Nxt is the first offset to be placed on the right page.
*/
temp = (off + 1) * sizeof(indx_t);
_DBFIT(temp, indx_t);
l->lower += (indx_t)temp;
/*
* If splitting the page that the cursor was on, the cursor has to be
* adjusted to point to the same record as before the split. If the
* cursor is at or past the skipped slot, the cursor is incremented by
* one. If the cursor is on the right page, it is decremented by the
* number of records split to the left page.
*/
c = &t->bt_cursor;
if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
if (c->pg.index >= skip)
++c->pg.index;
if (c->pg.index < nxt) /* Left page. */
c->pg.pgno = l->pgno;
else { /* Right page. */
c->pg.pgno = r->pgno;
c->pg.index -= nxt;
}
}
/*
* If the skipped index was on the left page, just return that page.
* Otherwise, adjust the skip index to reflect the new position on
* the right page.
*/
if (skip <= off) {
skip = MAX_PAGE_OFFSET;
rval = l;
} else {
rval = r;
*pskip -= nxt;
}
for (off = 0; nxt < top; ++off) {
if (skip == nxt) {
++off;
skip = MAX_PAGE_OFFSET;
}
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
src = bi = GETBINTERNAL(h, nxt);
nbytes = NBINTERNAL(bi->ksize);
break;
case P_BLEAF:
src = bl = GETBLEAF(h, nxt);
nbytes = NBLEAF(bl);
break;
case P_RINTERNAL:
src = GETRINTERNAL(h, nxt);
nbytes = NRINTERNAL;
break;
case P_RLEAF:
src = rl = GETRLEAF(h, nxt);
nbytes = NRLEAF(rl);
break;
default:
abort();
}
++nxt;
r->linp[off] = r->upper -= nbytes;
memmove((char *)(void *)r + r->upper, src, nbytes);
}
temp = off * sizeof(indx_t);
_DBFIT(temp, indx_t);
r->lower += (indx_t)temp;
/* If the key is being appended to the page, adjust the index. */
if (skip == top)
r->lower += sizeof(indx_t);
return (rval);
}
/*
* BT_PRESERVE -- Mark a chain of pages as used by an internal node.
*
* Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
* record that references them gets deleted. Chains pointed to by internal
* pages never get deleted. This routine marks a chain as pointed to by an
* internal page.
*
* Parameters:
* t: tree
* pg: page number of first page in the chain.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
static int
bt_preserve(BTREE *t, pgno_t pg)
{
PAGE *h;
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
h->flags |= P_PRESERVE;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* REC_TOTAL -- Return the number of recno entries below a page.
*
* Parameters:
* h: page
*
* Returns:
* The number of recno entries below a page.
*
* XXX
* These values could be set by the bt_psplit routine. The problem is that the
* entry has to be popped off of the stack etc. or the values have to be passed
* all the way back to bt_split/bt_rroot and it's not very clean.
*/
static recno_t
rec_total(PAGE *h)
{
recno_t recs;
indx_t nxt, top;
for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
recs += GETRINTERNAL(h, nxt)->nrecs;
return (recs);
}

View File

@@ -0,0 +1,252 @@
/* $NetBSD: bt_utils.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: bt_utils.c,v 1.13 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: bt_utils.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/param.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "btree.h"
/*
* __bt_ret --
* Build return key/data pair.
*
* Parameters:
* t: tree
* e: key/data pair to be returned
* key: user's key structure (NULL if not to be filled in)
* rkey: memory area to hold key
* data: user's data structure (NULL if not to be filled in)
* rdata: memory area to hold data
* copy: always copy the key/data item
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_ret(BTREE *t, EPG *e, DBT *key, DBT *rkey, DBT *data, DBT *rdata, int copy)
{
BLEAF *bl;
void *p;
bl = GETBLEAF(e->page, e->index);
/*
* We must copy big keys/data to make them contigous. Otherwise,
* leave the page pinned and don't copy unless the user specified
* concurrent access.
*/
if (key == NULL)
goto dataonly;
if (bl->flags & P_BIGKEY) {
if (__ovfl_get(t, bl->bytes,
&key->size, &rkey->data, &rkey->size))
return (RET_ERROR);
key->data = rkey->data;
} else if (copy || F_ISSET(t, B_DB_LOCK)) {
if (bl->ksize > rkey->size) {
p = (void *)(rkey->data == NULL ?
malloc(bl->ksize) : realloc(rkey->data, bl->ksize));
if (p == NULL)
return (RET_ERROR);
rkey->data = p;
rkey->size = bl->ksize;
}
memmove(rkey->data, bl->bytes, bl->ksize);
key->size = bl->ksize;
key->data = rkey->data;
} else {
key->size = bl->ksize;
key->data = bl->bytes;
}
dataonly:
if (data == NULL)
return (RET_SUCCESS);
if (bl->flags & P_BIGDATA) {
if (__ovfl_get(t, bl->bytes + bl->ksize,
&data->size, &rdata->data, &rdata->size))
return (RET_ERROR);
data->data = rdata->data;
} else if (copy || F_ISSET(t, B_DB_LOCK)) {
/* Use +1 in case the first record retrieved is 0 length. */
if (bl->dsize + 1 > rdata->size) {
p = (void *)(rdata->data == NULL ?
malloc(bl->dsize + 1) :
realloc(rdata->data, bl->dsize + 1));
if (p == NULL)
return (RET_ERROR);
rdata->data = p;
rdata->size = bl->dsize + 1;
}
memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
data->size = bl->dsize;
data->data = rdata->data;
} else {
data->size = bl->dsize;
data->data = bl->bytes + bl->ksize;
}
return (RET_SUCCESS);
}
/*
* __BT_CMP -- Compare a key to a given record.
*
* Parameters:
* t: tree
* k1: DBT pointer of first arg to comparison
* e: pointer to EPG for comparison
*
* Returns:
* < 0 if k1 is < record
* = 0 if k1 is = record
* > 0 if k1 is > record
*/
int
__bt_cmp(BTREE *t, const DBT *k1, EPG *e)
{
BINTERNAL *bi;
BLEAF *bl;
DBT k2;
PAGE *h;
void *bigkey;
/*
* The left-most key on internal pages, at any level of the tree, is
* guaranteed by the following code to be less than any user key.
* This saves us from having to update the leftmost key on an internal
* page when the user inserts a new key in the tree smaller than
* anything we've yet seen.
*/
h = e->page;
if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
return (1);
bigkey = NULL;
if (h->flags & P_BLEAF) {
bl = GETBLEAF(h, e->index);
if (bl->flags & P_BIGKEY)
bigkey = bl->bytes;
else {
k2.data = bl->bytes;
k2.size = bl->ksize;
}
} else {
bi = GETBINTERNAL(h, e->index);
if (bi->flags & P_BIGKEY)
bigkey = bi->bytes;
else {
k2.data = bi->bytes;
k2.size = bi->ksize;
}
}
if (bigkey) {
if (__ovfl_get(t, bigkey,
&k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
return (RET_ERROR);
k2.data = t->bt_rdata.data;
}
return ((*t->bt_cmp)(k1, &k2));
}
/*
* __BT_DEFCMP -- Default comparison routine.
*
* Parameters:
* a: DBT #1
* b: DBT #2
*
* Returns:
* < 0 if a is < b
* = 0 if a is = b
* > 0 if a is > b
*/
int
__bt_defcmp(const DBT *a, const DBT *b)
{
size_t len;
uint8_t *p1, *p2;
/*
* XXX
* If a size_t doesn't fit in an int, this routine can lose.
* What we need is a integral type which is guaranteed to be
* larger than a size_t, and there is no such thing.
*/
len = MIN(a->size, b->size);
for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
if (*p1 != *p2)
return ((int)*p1 - (int)*p2);
return ((int)a->size - (int)b->size);
}
/*
* __BT_DEFPFX -- Default prefix routine.
*
* Parameters:
* a: DBT #1
* b: DBT #2
*
* Returns:
* Number of bytes needed to distinguish b from a.
*/
size_t
__bt_defpfx(const DBT *a, const DBT *b)
{
uint8_t *p1, *p2;
size_t cnt, len;
cnt = 1;
len = MIN(a->size, b->size);
for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
if (*p1 != *p2)
return (cnt);
/* a->size must be <= b->size, or they wouldn't be in this order. */
return (a->size < b->size ? a->size + 1 : a->size);
}

View File

@@ -0,0 +1,439 @@
/* $NetBSD: btree.h,v 1.3 2008/10/28 15:06:26 joerg Exp $ */
/* NetBSD: btree.h,v 1.16 2008/08/26 21:18:38 joerg Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)btree.h 8.11 (Berkeley) 8/17/94
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
/* Macros to set/clear/test flags. */
#define F_SET(p, f) (p)->flags |= (f)
#define F_CLR(p, f) (p)->flags &= ~(f)
#define F_ISSET(p, f) ((p)->flags & (f))
#include <nbcompat/mpool.h>
#define DEFMINKEYPAGE (2) /* Minimum keys per page */
#define MINCACHE (5) /* Minimum cached pages */
#define MINPSIZE (512) /* Minimum page size */
/*
* Page 0 of a btree file contains a copy of the meta-data. This page is also
* used as an out-of-band page, i.e. page pointers that point to nowhere point
* to page 0. Page 1 is the root of the btree.
*/
#define P_INVALID 0 /* Invalid tree page number. */
#define P_META 0 /* Tree metadata page number. */
#define P_ROOT 1 /* Tree root page number. */
/*
* There are five page layouts in the btree: btree internal pages (BINTERNAL),
* btree leaf pages (BLEAF), recno internal pages (RINTERNAL), recno leaf pages
* (RLEAF) and overflow pages. All five page types have a page header (PAGE).
* This implementation requires that values within structures NOT be padded.
* (ANSI C permits random padding.) If your compiler pads randomly you'll have
* to do some work to get this package to run.
*/
typedef struct _page {
pgno_t pgno; /* this page's page number */
pgno_t prevpg; /* left sibling */
pgno_t nextpg; /* right sibling */
#define P_BINTERNAL 0x01 /* btree internal page */
#define P_BLEAF 0x02 /* leaf page */
#define P_OVERFLOW 0x04 /* overflow page */
#define P_RINTERNAL 0x08 /* recno internal page */
#define P_RLEAF 0x10 /* leaf page */
#define P_TYPE 0x1f /* type mask */
#define P_PRESERVE 0x20 /* never delete this chain of pages */
uint32_t flags;
indx_t lower; /* lower bound of free space on page */
indx_t upper; /* upper bound of free space on page */
indx_t linp[1]; /* indx_t-aligned VAR. LENGTH DATA */
} PAGE;
/* First and next index. */
#define BTDATAOFF \
(sizeof(pgno_t) + sizeof(pgno_t) + sizeof(pgno_t) + \
sizeof(uint32_t) + sizeof(indx_t) + sizeof(indx_t))
#define _NEXTINDEX(p) (((p)->lower - BTDATAOFF) / sizeof(indx_t))
#ifdef _DIAGNOSTIC
static __inline indx_t
NEXTINDEX(const PAGE *p) {
size_t x = _NEXTINDEX(p);
_DBFIT(x, indx_t);
return (indx_t)x;
}
#else
#define NEXTINDEX(p) (indx_t)_NEXTINDEX(p)
#endif
/*
* For pages other than overflow pages, there is an array of offsets into the
* rest of the page immediately following the page header. Each offset is to
* an item which is unique to the type of page. The h_lower offset is just
* past the last filled-in index. The h_upper offset is the first item on the
* page. Offsets are from the beginning of the page.
*
* If an item is too big to store on a single page, a flag is set and the item
* is a { page, size } pair such that the page is the first page of an overflow
* chain with size bytes of item. Overflow pages are simply bytes without any
* external structure.
*
* The page number and size fields in the items are pgno_t-aligned so they can
* be manipulated without copying. (This presumes that 32 bit items can be
* manipulated on this system.)
*/
#define BTLALIGN(n) (((n) + sizeof(pgno_t) - 1) & ~(sizeof(pgno_t) - 1))
#define NOVFLSIZE (sizeof(pgno_t) + sizeof(uint32_t))
/*
* For the btree internal pages, the item is a key. BINTERNALs are {key, pgno}
* pairs, such that the key compares less than or equal to all of the records
* on that page. For a tree without duplicate keys, an internal page with two
* consecutive keys, a and b, will have all records greater than or equal to a
* and less than b stored on the page associated with a. Duplicate keys are
* somewhat special and can cause duplicate internal and leaf page records and
* some minor modifications of the above rule.
*/
typedef struct _binternal {
uint32_t ksize; /* key size */
pgno_t pgno; /* page number stored on */
#define P_BIGDATA 0x01 /* overflow data */
#define P_BIGKEY 0x02 /* overflow key */
uint8_t flags;
char bytes[1]; /* data */
} BINTERNAL;
/* Get the page's BINTERNAL structure at index indx. */
#define GETBINTERNAL(pg, indx) \
((BINTERNAL *)(void *)((char *)(void *)(pg) + (pg)->linp[indx]))
/* Get the number of bytes in the entry. */
#define _NBINTERNAL(len) \
BTLALIGN(sizeof(uint32_t) + sizeof(pgno_t) + sizeof(uint8_t) + (len))
#ifdef _DIAGNOSTIC
static __inline uint32_t
NBINTERNAL(uint32_t len) {
size_t x = _NBINTERNAL(len);
_DBFIT(x, uint32_t);
return (uint32_t)x;
}
#else
#define NBINTERNAL(len) (uint32_t)_NBINTERNAL(len)
#endif
/* Copy a BINTERNAL entry to the page. */
#define WR_BINTERNAL(p, size, pgno, flags) do { \
_DBFIT(size, uint32_t); \
*(uint32_t *)(void *)p = (uint32_t)size; \
p += sizeof(uint32_t); \
*(pgno_t *)(void *)p = pgno; \
p += sizeof(pgno_t); \
*(uint8_t *)(void *)p = flags; \
p += sizeof(uint8_t); \
} while (/*CONSTCOND*/0)
/*
* For the recno internal pages, the item is a page number with the number of
* keys found on that page and below.
*/
typedef struct _rinternal {
recno_t nrecs; /* number of records */
pgno_t pgno; /* page number stored below */
} RINTERNAL;
/* Get the page's RINTERNAL structure at index indx. */
#define GETRINTERNAL(pg, indx) \
((RINTERNAL *)(void *)((char *)(void *)(pg) + (pg)->linp[indx]))
/* Get the number of bytes in the entry. */
#define NRINTERNAL \
BTLALIGN(sizeof(recno_t) + sizeof(pgno_t))
/* Copy a RINTERAL entry to the page. */
#define WR_RINTERNAL(p, nrecs, pgno) do { \
*(recno_t *)(void *)p = nrecs; \
p += sizeof(recno_t); \
*(pgno_t *)(void *)p = pgno; \
} while (/*CONSTCOND*/0)
/* For the btree leaf pages, the item is a key and data pair. */
typedef struct _bleaf {
uint32_t ksize; /* size of key */
uint32_t dsize; /* size of data */
uint8_t flags; /* P_BIGDATA, P_BIGKEY */
char bytes[1]; /* data */
} BLEAF;
/* Get the page's BLEAF structure at index indx. */
#define GETBLEAF(pg, indx) \
((BLEAF *)(void *)((char *)(void *)(pg) + (pg)->linp[indx]))
/* Get the number of bytes in the user's key/data pair. */
#define _NBLEAFDBT(ksize, dsize) \
BTLALIGN(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) + \
(ksize) + (dsize))
#ifdef _DIAGNOSTIC
static __inline uint32_t
NBLEAFDBT(size_t k, size_t d) {
size_t x = _NBLEAFDBT(k, d);
_DBFIT(x, uint32_t);
return (uint32_t)x;
}
#else
#define NBLEAFDBT(p, q) (uint32_t)_NBLEAFDBT(p, q)
#endif
/* Get the number of bytes in the entry. */
#define NBLEAF(p) NBLEAFDBT((p)->ksize, (p)->dsize)
/* Copy a BLEAF entry to the page. */
#define WR_BLEAF(p, key, data, flags) do { \
_DBFIT(key->size, uint32_t); \
*(uint32_t *)(void *)p = (uint32_t)key->size; \
p += sizeof(uint32_t); \
_DBFIT(data->size, uint32_t); \
*(uint32_t *)(void *)p = (uint32_t)data->size; \
p += sizeof(uint32_t); \
*(uint8_t *)(void *)p = flags; \
p += sizeof(uint8_t); \
(void)memmove(p, key->data, key->size); \
p += key->size; \
(void)memmove(p, data->data, data->size); \
} while (/*CONSTCOND*/0)
/* For the recno leaf pages, the item is a data entry. */
typedef struct _rleaf {
uint32_t dsize; /* size of data */
uint8_t flags; /* P_BIGDATA */
char bytes[1];
} RLEAF;
/* Get the page's RLEAF structure at index indx. */
#define GETRLEAF(pg, indx) \
((RLEAF *)(void *)((char *)(void *)(pg) + (pg)->linp[indx]))
#define _NRLEAFDBT(dsize) \
BTLALIGN(sizeof(uint32_t) + sizeof(uint8_t) + (dsize))
#ifdef _DIAGNOSTIC
static __inline uint32_t
NRLEAFDBT(size_t d) {
size_t x = _NRLEAFDBT(d);
_DBFIT(x, uint32_t);
return (uint32_t)x;
}
#else
#define NRLEAFDBT(d) (uint32_t)_NRLEAFDBT(d)
#endif
/* Get the number of bytes in the entry. */
#define NRLEAF(p) NRLEAFDBT((p)->dsize)
/* Get the number of bytes from the user's data. */
/* Copy a RLEAF entry to the page. */
#define WR_RLEAF(p, data, flags) do { \
_DBFIT(data->size, uint32_t); \
*(uint32_t *)(void *)p = (uint32_t)data->size; \
p += sizeof(uint32_t); \
*(uint8_t *)(void *)p = flags; \
p += sizeof(uint8_t); \
memmove(p, data->data, data->size); \
} while (/*CONSTCOND*/0)
/*
* A record in the tree is either a pointer to a page and an index in the page
* or a page number and an index. These structures are used as a cursor, stack
* entry and search returns as well as to pass records to other routines.
*
* One comment about searches. Internal page searches must find the largest
* record less than key in the tree so that descents work. Leaf page searches
* must find the smallest record greater than key so that the returned index
* is the record's correct position for insertion.
*/
typedef struct _epgno {
pgno_t pgno; /* the page number */
indx_t index; /* the index on the page */
} EPGNO;
typedef struct _epg {
PAGE *page; /* the (pinned) page */
indx_t index; /* the index on the page */
} EPG;
/*
* About cursors. The cursor (and the page that contained the key/data pair
* that it referenced) can be deleted, which makes things a bit tricky. If
* there are no duplicates of the cursor key in the tree (i.e. B_NODUPS is set
* or there simply aren't any duplicates of the key) we copy the key that it
* referenced when it's deleted, and reacquire a new cursor key if the cursor
* is used again. If there are duplicates keys, we move to the next/previous
* key, and set a flag so that we know what happened. NOTE: if duplicate (to
* the cursor) keys are added to the tree during this process, it is undefined
* if they will be returned or not in a cursor scan.
*
* The flags determine the possible states of the cursor:
*
* CURS_INIT The cursor references *something*.
* CURS_ACQUIRE The cursor was deleted, and a key has been saved so that
* we can reacquire the right position in the tree.
* CURS_AFTER, CURS_BEFORE
* The cursor was deleted, and now references a key/data pair
* that has not yet been returned, either before or after the
* deleted key/data pair.
* XXX
* This structure is broken out so that we can eventually offer multiple
* cursors as part of the DB interface.
*/
typedef struct _cursor {
EPGNO pg; /* B: Saved tree reference. */
DBT key; /* B: Saved key, or key.data == NULL. */
recno_t rcursor; /* R: recno cursor (1-based) */
#define CURS_ACQUIRE 0x01 /* B: Cursor needs to be reacquired. */
#define CURS_AFTER 0x02 /* B: Unreturned cursor after key. */
#define CURS_BEFORE 0x04 /* B: Unreturned cursor before key. */
#define CURS_INIT 0x08 /* RB: Cursor initialized. */
uint8_t flags;
} CURSOR;
/*
* The metadata of the tree. The nrecs field is used only by the RECNO code.
* This is because the btree doesn't really need it and it requires that every
* put or delete call modify the metadata.
*/
typedef struct _btmeta {
uint32_t magic; /* magic number */
uint32_t version; /* version */
uint32_t psize; /* page size */
uint32_t free; /* page number of first free page */
uint32_t nrecs; /* R: number of records */
#define SAVEMETA (B_NODUPS | R_RECNO)
uint32_t flags; /* bt_flags & SAVEMETA */
} BTMETA;
/* The in-memory btree/recno data structure. */
typedef struct _btree {
MPOOL *bt_mp; /* memory pool cookie */
DB *bt_dbp; /* pointer to enclosing DB */
EPG bt_cur; /* current (pinned) page */
PAGE *bt_pinned; /* page pinned across calls */
CURSOR bt_cursor; /* cursor */
#define BT_PUSH(t, p, i) { \
t->bt_sp->pgno = p; \
t->bt_sp->index = i; \
++t->bt_sp; \
}
#define BT_POP(t) (t->bt_sp == t->bt_stack ? NULL : --t->bt_sp)
#define BT_CLR(t) (t->bt_sp = t->bt_stack)
EPGNO bt_stack[50]; /* stack of parent pages */
EPGNO *bt_sp; /* current stack pointer */
DBT bt_rkey; /* returned key */
DBT bt_rdata; /* returned data */
int bt_fd; /* tree file descriptor */
pgno_t bt_free; /* next free page */
uint32_t bt_psize; /* page size */
indx_t bt_ovflsize; /* cut-off for key/data overflow */
int bt_lorder; /* byte order */
/* sorted order */
enum { NOT, BACK, FORWARD } bt_order;
EPGNO bt_last; /* last insert */
/* B: key comparison function */
int (*bt_cmp)(const DBT *, const DBT *);
/* B: prefix comparison function */
size_t (*bt_pfx)(const DBT *, const DBT *);
/* R: recno input function */
int (*bt_irec)(struct _btree *, recno_t);
FILE *bt_rfp; /* R: record FILE pointer */
int bt_rfd; /* R: record file descriptor */
caddr_t bt_cmap; /* R: current point in mapped space */
caddr_t bt_smap; /* R: start of mapped space */
caddr_t bt_emap; /* R: end of mapped space */
size_t bt_msize; /* R: size of mapped region. */
recno_t bt_nrecs; /* R: number of records */
size_t bt_reclen; /* R: fixed record length */
uint8_t bt_bval; /* R: delimiting byte/pad character */
/*
* NB:
* B_NODUPS and R_RECNO are stored on disk, and may not be changed.
*/
#define B_INMEM 0x00001 /* in-memory tree */
#define B_METADIRTY 0x00002 /* need to write metadata */
#define B_MODIFIED 0x00004 /* tree modified */
#define B_NEEDSWAP 0x00008 /* if byte order requires swapping */
#define B_RDONLY 0x00010 /* read-only tree */
#define B_NODUPS 0x00020 /* no duplicate keys permitted */
#define R_RECNO 0x00080 /* record oriented tree */
#define R_CLOSEFP 0x00040 /* opened a file pointer */
#define R_EOF 0x00100 /* end of input file reached. */
#define R_FIXLEN 0x00200 /* fixed length records */
#define R_MEMMAPPED 0x00400 /* memory mapped file. */
#define R_INMEM 0x00800 /* in-memory file */
#define R_MODIFIED 0x01000 /* modified file */
#define R_RDONLY 0x02000 /* read-only file */
#define B_DB_LOCK 0x04000 /* DB_LOCK specified. */
#define B_DB_SHMEM 0x08000 /* DB_SHMEM specified. */
#define B_DB_TXN 0x10000 /* DB_TXN specified. */
uint32_t flags;
} BTREE;
#include <errno.h>
#ifndef EFTYPE
#define EFTYPE EINVAL
#endif
#include "extern.h"

View File

@@ -0,0 +1,73 @@
/* $NetBSD: extern.h,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: extern.h,v 1.12 2008/09/26 11:41:06 tsutsui Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.10 (Berkeley) 7/20/94
*/
#ifndef _BTREE_EXTERN_H_
#define _BTREE_EXTERN_H_
int __bt_close(DB *);
int __bt_cmp(BTREE *, const DBT *, EPG *);
int __bt_crsrdel(BTREE *, EPGNO *);
int __bt_defcmp(const DBT *, const DBT *);
size_t __bt_defpfx(const DBT *, const DBT *);
int __bt_delete(const DB *, const DBT *, unsigned int);
int __bt_dleaf(BTREE *, const DBT *, PAGE *, unsigned int);
int __bt_fd(const DB *);
int __bt_free(BTREE *, PAGE *);
int __bt_get(const DB *, const DBT *, DBT *, unsigned int);
PAGE *__bt_new(BTREE *, pgno_t *);
void __bt_pgin(void *, pgno_t, void *);
void __bt_pgout(void *, pgno_t, void *);
int __bt_push(BTREE *, pgno_t, int);
int __bt_put(const DB *dbp, DBT *, const DBT *, unsigned int);
int __bt_ret(BTREE *, EPG *, DBT *, DBT *, DBT *, DBT *, int);
EPG *__bt_search(BTREE *, const DBT *, int *);
int __bt_seq(const DB *, DBT *, DBT *, unsigned int);
void __bt_setcur(BTREE *, pgno_t, unsigned int);
int __bt_split(BTREE *, PAGE *,
const DBT *, const DBT *, int, size_t, uint32_t);
int __bt_sync(const DB *, unsigned int);
int __ovfl_delete(BTREE *, void *);
int __ovfl_get(BTREE *, void *, size_t *, void **, size_t *);
int __ovfl_put(BTREE *, const DBT *, pgno_t *);
#ifdef DEBUG
void __bt_dmpage(PAGE *);
void __bt_dnpage(DB *, pgno_t);
void __bt_dpage(PAGE *);
void __bt_dump(DB *);
#endif
#ifdef STATISTICS
void __bt_stat(DB *);
#endif
#endif /* _BTREE_EXTERN_H_ */

View File

@@ -0,0 +1,109 @@
/* $NetBSD: db.c,v 1.3 2010/01/24 12:29:48 obache Exp $ */
/* NetBSD: db.c,v 1.16 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: db.c,v 1.3 2010/01/24 12:29:48 obache Exp $");
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <nbcompat/db.h>
static int __dberr(void);
#if 0
#ifdef __weak_alias
__weak_alias(dbopen,_dbopen)
#endif
#endif
DB *
dbopen(const char *fname, int flags, mode_t mode, DBTYPE type,
const void *openinfo)
{
#ifndef O_EXLOCK
#define O_EXLOCK 0
#endif
#ifndef O_SHLOCK
#define O_SHLOCK 0
#endif
#define DB_FLAGS (DB_LOCK | DB_SHMEM | DB_TXN)
#define USE_OPEN_FLAGS \
(O_CREAT | O_EXCL | O_EXLOCK | O_NONBLOCK | O_RDONLY | \
O_RDWR | O_SHLOCK | O_TRUNC)
if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
switch (type) {
case DB_BTREE:
return (__bt_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, (int)(flags & DB_FLAGS)));
case DB_HASH:
return (__hash_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, (int)(flags & DB_FLAGS)));
case DB_RECNO:
return (__rec_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, (int)(flags & DB_FLAGS)));
}
errno = EINVAL;
return (NULL);
}
static int
__dberr(void)
{
return (RET_ERROR);
}
/*
* __DBPANIC -- Stop.
*
* Parameters:
* dbp: pointer to the DB structure.
*/
void
__dbpanic(DB *dbp)
{
/* The only thing that can succeed is a close. */
dbp->del = (int (*)(const struct __db *, const DBT*, u_int))__dberr;
dbp->fd = (int (*)(const struct __db *))__dberr;
dbp->get = (int (*)(const struct __db *, const DBT*, DBT *, u_int))__dberr;
dbp->put = (int (*)(const struct __db *, DBT *, const DBT *, u_int))__dberr;
dbp->seq = (int (*)(const struct __db *, DBT *, DBT *, u_int))__dberr;
dbp->sync = (int (*)(const struct __db *, u_int))__dberr;
}

View File

@@ -0,0 +1,64 @@
/* $NetBSD: extern.h,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: extern.h,v 1.9 2008/08/26 21:18:38 joerg Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.4 (Berkeley) 6/16/94
*/
BUFHEAD *__add_ovflpage(HTAB *, BUFHEAD *);
int __addel(HTAB *, BUFHEAD *, const DBT *, const DBT *);
int __big_delete(HTAB *, BUFHEAD *);
int __big_insert(HTAB *, BUFHEAD *, const DBT *, const DBT *);
int __big_keydata(HTAB *, BUFHEAD *, DBT *, DBT *, int);
int __big_return(HTAB *, BUFHEAD *, int, DBT *, int);
int __big_split(HTAB *, BUFHEAD *, BUFHEAD *, BUFHEAD *,
int, uint32_t, SPLIT_RETURN *);
int __buf_free(HTAB *, int, int);
void __buf_init(HTAB *, u_int);
uint32_t __call_hash(HTAB *, char *, int);
int __delpair(HTAB *, BUFHEAD *, int);
int __expand_table(HTAB *);
int __find_bigpair(HTAB *, BUFHEAD *, int, char *, int);
uint16_t __find_last_page(HTAB *, BUFHEAD **);
void __free_ovflpage(HTAB *, BUFHEAD *);
BUFHEAD *__get_buf(HTAB *, uint32_t, BUFHEAD *, int);
int __get_page(HTAB *, char *, uint32_t, int, int, int);
int __ibitmap(HTAB *, int, int, int);
uint32_t __log2(uint32_t);
int __put_page(HTAB *, char *, uint32_t, int, int);
void __reclaim_buf(HTAB *, BUFHEAD *);
int __split_page(HTAB *, uint32_t, uint32_t);
/* Default hash routine. */
extern uint32_t (*__default_hash)(const void *, size_t);
#ifdef HASH_STATISTICS
extern int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
#endif

View File

@@ -0,0 +1,977 @@
/* $NetBSD: hash.c,v 1.4 2012/05/15 16:45:45 christos Exp $ */
/* NetBSD: hash.c,v 1.30 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash.c,v 1.4 2012/05/15 16:45:45 christos Exp $");
#include <nbcompat/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
#ifdef BROKEN_PWRITE
#include "../pwrite.c"
#endif
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(size_t)(const void *)(a))
#endif
static int alloc_segs(HTAB *, int);
static int flush_meta(HTAB *);
static int hash_access(HTAB *, ACTION, DBT *, DBT *);
static int hash_close(DB *);
static int hash_delete(const DB *, const DBT *, uint32_t);
static int hash_fd(const DB *);
static int hash_get(const DB *, const DBT *, DBT *, uint32_t);
static int hash_put(const DB *, DBT *, const DBT *, uint32_t);
static void *hash_realloc(SEGMENT **, size_t, size_t);
static int hash_seq(const DB *, DBT *, DBT *, uint32_t);
static int hash_sync(const DB *, uint32_t);
static int hdestroy(HTAB *);
static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
static int init_htab(HTAB *, size_t);
#if BYTE_ORDER == LITTLE_ENDIAN
static void swap_header(HTAB *);
static void swap_header_copy(HASHHDR *, HASHHDR *);
#endif
/* Fast arithmetic, relying on powers of 2, */
#define MOD(x, y) ((x) & ((y) - 1))
#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
/* Return values */
#define SUCCESS (0)
#define ERROR (-1)
#define ABNORMAL (1)
#ifdef HASH_STATISTICS
int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
#endif
/************************** INTERFACE ROUTINES ***************************/
/* OPEN/CLOSE */
/* ARGSUSED */
DB *
__hash_open(const char *file, int flags, mode_t mode, const HASHINFO *info,
int dflags)
{
HTAB *hashp;
struct stat statbuf;
DB *dbp;
int bpages, new_table, nsegs, save_errno;
ssize_t hdrsize;
if ((flags & O_ACCMODE) == O_WRONLY) {
errno = EINVAL;
return (NULL);
}
if (!(hashp = calloc(1, sizeof(HTAB))))
return (NULL);
hashp->fp = -1;
/*
* Even if user wants write only, we need to be able to read
* the actual file, so we need to open it read/write. But, the
* field in the hashp structure needs to be accurate so that
* we can check accesses.
*/
hashp->flags = flags;
new_table = 0;
if (!file || (flags & O_TRUNC) ||
(stat(file, &statbuf) && (errno == ENOENT))) {
if (errno == ENOENT)
errno = 0; /* Just in case someone looks at errno */
new_table = 1;
}
if (file) {
if ((hashp->fp = open(file, flags, mode)) == -1)
RETURN_ERROR(errno, error0);
if (fcntl(hashp->fp, F_SETFD, FD_CLOEXEC) == -1)
RETURN_ERROR(errno, error1);
if (fstat(hashp->fp, &statbuf) == -1)
RETURN_ERROR(errno, error1);
new_table |= statbuf.st_size == 0;
}
if (new_table) {
if (!(hashp = init_hash(hashp, file, info)))
RETURN_ERROR(errno, error1);
} else {
/* Table already exists */
if (info && info->hash)
hashp->hash = info->hash;
else
hashp->hash = __default_hash;
hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
#if BYTE_ORDER == LITTLE_ENDIAN
swap_header(hashp);
#endif
if (hdrsize == -1)
RETURN_ERROR(errno, error1);
if (hdrsize != sizeof(HASHHDR))
RETURN_ERROR(EFTYPE, error1);
/* Verify file type, versions and hash function */
if (hashp->MAGIC != HASHMAGIC)
RETURN_ERROR(EFTYPE, error1);
#define OLDHASHVERSION 1
if (hashp->VERSION != HASHVERSION &&
hashp->VERSION != OLDHASHVERSION)
RETURN_ERROR(EFTYPE, error1);
if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
RETURN_ERROR(EFTYPE, error1);
/*
* Figure out how many segments we need. Max_Bucket is the
* maximum bucket number, so the number of buckets is
* max_bucket + 1.
*/
nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
hashp->SGSIZE;
hashp->nsegs = 0;
if (alloc_segs(hashp, nsegs))
/*
* If alloc_segs fails, table will have been destroyed
* and errno will have been set.
*/
return (NULL);
/* Read in bitmaps */
bpages = (hashp->SPARES[hashp->OVFL_POINT] +
(unsigned int)(hashp->BSIZE << BYTE_SHIFT) - 1) >>
(hashp->BSHIFT + BYTE_SHIFT);
hashp->nmaps = bpages;
(void)memset(&hashp->mapp[0], 0, bpages * sizeof(uint32_t *));
}
/* Initialize Buffer Manager */
if (info && info->cachesize)
__buf_init(hashp, info->cachesize);
else
__buf_init(hashp, DEF_BUFSIZE);
hashp->new_file = new_table;
hashp->save_file = file && (hashp->flags & O_RDWR);
hashp->cbucket = -1;
if (!(dbp = malloc(sizeof(DB)))) {
save_errno = errno;
hdestroy(hashp);
errno = save_errno;
return (NULL);
}
dbp->internal = hashp;
dbp->close = hash_close;
dbp->del = hash_delete;
dbp->fd = hash_fd;
dbp->get = hash_get;
dbp->put = hash_put;
dbp->seq = hash_seq;
dbp->sync = hash_sync;
dbp->type = DB_HASH;
#ifdef DEBUG
(void)fprintf(stderr,
"%s\n%s%p\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
"init_htab:",
"TABLE POINTER ", hashp,
"BUCKET SIZE ", hashp->BSIZE,
"BUCKET SHIFT ", hashp->BSHIFT,
"DIRECTORY SIZE ", hashp->DSIZE,
"SEGMENT SIZE ", hashp->SGSIZE,
"SEGMENT SHIFT ", hashp->SSHIFT,
"FILL FACTOR ", hashp->FFACTOR,
"MAX BUCKET ", hashp->MAX_BUCKET,
"OVFL POINT ", hashp->OVFL_POINT,
"LAST FREED ", hashp->LAST_FREED,
"HIGH MASK ", hashp->HIGH_MASK,
"LOW MASK ", hashp->LOW_MASK,
"NSEGS ", hashp->nsegs,
"NKEYS ", hashp->NKEYS);
#endif
#ifdef HASH_STATISTICS
hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
#endif
return (dbp);
error1:
if (hashp != NULL)
(void)close(hashp->fp);
error0:
free(hashp);
errno = save_errno;
return (NULL);
}
static int
hash_close(DB *dbp)
{
HTAB *hashp;
int retval;
if (!dbp)
return (ERROR);
hashp = dbp->internal;
retval = hdestroy(hashp);
free(dbp);
return (retval);
}
static int
hash_fd(const DB *dbp)
{
HTAB *hashp;
if (!dbp)
return (ERROR);
hashp = dbp->internal;
if (hashp->fp == -1) {
errno = ENOENT;
return (-1);
}
return (hashp->fp);
}
/************************** LOCAL CREATION ROUTINES **********************/
static HTAB *
init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
{
struct stat statbuf;
int nelem;
nelem = 1;
hashp->NKEYS = 0;
hashp->LORDER = BYTE_ORDER;
hashp->BSIZE = DEF_BUCKET_SIZE;
hashp->BSHIFT = DEF_BUCKET_SHIFT;
hashp->SGSIZE = DEF_SEGSIZE;
hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
hashp->DSIZE = DEF_DIRSIZE;
hashp->FFACTOR = DEF_FFACTOR;
hashp->hash = __default_hash;
memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
/* Fix bucket size to be optimal for file system */
if (file != NULL) {
if (stat(file, &statbuf))
return (NULL);
hashp->BSIZE = MIN(statbuf.st_blksize, MAX_BSIZE);
hashp->BSHIFT = __log2((uint32_t)hashp->BSIZE);
}
if (info) {
if (info->bsize) {
/* Round pagesize up to power of 2 */
hashp->BSHIFT = __log2(info->bsize);
hashp->BSIZE = 1 << hashp->BSHIFT;
if (hashp->BSIZE > MAX_BSIZE) {
errno = EINVAL;
return (NULL);
}
}
if (info->ffactor)
hashp->FFACTOR = info->ffactor;
if (info->hash)
hashp->hash = info->hash;
if (info->nelem)
nelem = info->nelem;
if (info->lorder) {
if (info->lorder != BIG_ENDIAN &&
info->lorder != LITTLE_ENDIAN) {
errno = EINVAL;
return (NULL);
}
hashp->LORDER = info->lorder;
}
}
/* init_htab should destroy the table and set errno if it fails */
if (init_htab(hashp, (size_t)nelem))
return (NULL);
else
return (hashp);
}
/*
* This calls alloc_segs which may run out of memory. Alloc_segs will destroy
* the table and set errno, so we just pass the error information along.
*
* Returns 0 on No Error
*/
static int
init_htab(HTAB *hashp, size_t nelem)
{
int nbuckets;
uint32_t nsegs;
int l2;
/*
* Divide number of elements by the fill factor and determine a
* desired number of buckets. Allocate space for the next greater
* power of two number of buckets.
*/
nelem = (nelem - 1) / hashp->FFACTOR + 1;
_DBFIT(nelem, uint32_t);
l2 = __log2(MAX((uint32_t)nelem, 2));
nbuckets = 1 << l2;
hashp->SPARES[l2] = l2 + 1;
hashp->SPARES[l2 + 1] = l2 + 1;
hashp->OVFL_POINT = l2;
hashp->LAST_FREED = 2;
/* First bitmap page is at: splitpoint l2 page offset 1 */
if (__ibitmap(hashp, (int)OADDR_OF(l2, 1), l2 + 1, 0))
return (-1);
hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
hashp->HIGH_MASK = (nbuckets << 1) - 1;
/* LINTED constant in conditional context */
hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
hashp->BSHIFT) + 1;
nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
nsegs = 1 << __log2(nsegs);
if (nsegs > hashp->DSIZE)
hashp->DSIZE = nsegs;
return (alloc_segs(hashp, (int)nsegs));
}
/********************** DESTROY/CLOSE ROUTINES ************************/
/*
* Flushes any changes to the file if necessary and destroys the hashp
* structure, freeing all allocated space.
*/
static int
hdestroy(HTAB *hashp)
{
int i, save_errno;
save_errno = 0;
#ifdef HASH_STATISTICS
(void)fprintf(stderr, "hdestroy: accesses %d collisions %d\n",
hash_accesses, hash_collisions);
(void)fprintf(stderr, "hdestroy: expansions %d\n",
hash_expansions);
(void)fprintf(stderr, "hdestroy: overflows %d\n",
hash_overflows);
(void)fprintf(stderr, "keys %d maxp %d segmentcount %d\n",
hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
for (i = 0; i < NCACHED; i++)
(void)fprintf(stderr,
"spares[%d] = %d\n", i, hashp->SPARES[i]);
#endif
/*
* Call on buffer manager to free buffers, and if required,
* write them to disk.
*/
if (__buf_free(hashp, 1, hashp->save_file))
save_errno = errno;
if (hashp->dir) {
free(*hashp->dir); /* Free initial segments */
/* Free extra segments */
while (hashp->exsegs--)
free(hashp->dir[--hashp->nsegs]);
free(hashp->dir);
}
if (flush_meta(hashp) && !save_errno)
save_errno = errno;
/* Free Bigmaps */
for (i = 0; i < hashp->nmaps; i++)
if (hashp->mapp[i])
free(hashp->mapp[i]);
if (hashp->fp != -1)
(void)close(hashp->fp);
free(hashp);
if (save_errno) {
errno = save_errno;
return (ERROR);
}
return (SUCCESS);
}
/*
* Write modified pages to disk
*
* Returns:
* 0 == OK
* -1 ERROR
*/
static int
hash_sync(const DB *dbp, uint32_t flags)
{
HTAB *hashp;
if (flags != 0) {
errno = EINVAL;
return (ERROR);
}
if (!dbp)
return (ERROR);
hashp = dbp->internal;
if (!hashp->save_file)
return (0);
if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
return (ERROR);
hashp->new_file = 0;
return (0);
}
/*
* Returns:
* 0 == OK
* -1 indicates that errno should be set
*/
static int
flush_meta(HTAB *hashp)
{
HASHHDR *whdrp;
#if BYTE_ORDER == LITTLE_ENDIAN
HASHHDR whdr;
#endif
int fp, i;
ssize_t wsize;
if (!hashp->save_file)
return (0);
hashp->MAGIC = HASHMAGIC;
hashp->VERSION = HASHVERSION;
hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
fp = hashp->fp;
whdrp = &hashp->hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
whdrp = &whdr;
swap_header_copy(&hashp->hdr, whdrp);
#endif
if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1)
return (-1);
else
if (wsize != sizeof(HASHHDR)) {
errno = EFTYPE;
hashp->err = errno;
return (-1);
}
for (i = 0; i < NCACHED; i++)
if (hashp->mapp[i])
if (__put_page(hashp, (char *)(void *)hashp->mapp[i],
(u_int)hashp->BITMAPS[i], 0, 1))
return (-1);
return (0);
}
/*******************************SEARCH ROUTINES *****************************/
/*
* All the access routines return
*
* Returns:
* 0 on SUCCESS
* 1 to indicate an external ERROR (i.e. key not found, etc)
* -1 to indicate an internal ERROR (i.e. out of memory, etc)
*/
static int
hash_get(const DB *dbp, const DBT *key, DBT *data, uint32_t flag)
{
HTAB *hashp;
hashp = dbp->internal;
if (flag) {
hashp->err = errno = EINVAL;
return (ERROR);
}
return (hash_access(hashp, HASH_GET, __UNCONST(key), data));
}
static int
hash_put(const DB *dbp, DBT *key, const DBT *data, uint32_t flag)
{
HTAB *hashp;
hashp = dbp->internal;
if (flag && flag != R_NOOVERWRITE) {
hashp->err = errno = EINVAL;
return (ERROR);
}
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
hashp->err = errno = EPERM;
return (ERROR);
}
/* LINTED const castaway */
return (hash_access(hashp, flag == R_NOOVERWRITE ?
HASH_PUTNEW : HASH_PUT, __UNCONST(key), __UNCONST(data)));
}
static int
hash_delete(const DB *dbp, const DBT *key, uint32_t flag)
{
HTAB *hashp;
hashp = dbp->internal;
if (flag && flag != R_CURSOR) {
hashp->err = errno = EINVAL;
return (ERROR);
}
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
hashp->err = errno = EPERM;
return (ERROR);
}
return hash_access(hashp, HASH_DELETE, __UNCONST(key), NULL);
}
/*
* Assume that hashp has been set in wrapper routine.
*/
static int
hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
{
BUFHEAD *rbufp;
BUFHEAD *bufp, *save_bufp;
uint16_t *bp;
int n, ndx, off;
size_t size;
char *kp;
uint16_t pageno;
#ifdef HASH_STATISTICS
hash_accesses++;
#endif
off = hashp->BSIZE;
size = key->size;
kp = (char *)key->data;
rbufp = __get_buf(hashp, __call_hash(hashp, kp, (int)size), NULL, 0);
if (!rbufp)
return (ERROR);
save_bufp = rbufp;
/* Pin the bucket chain */
rbufp->flags |= BUF_PIN;
for (bp = (uint16_t *)(void *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
if (bp[1] >= REAL_KEY) {
/* Real key/data pair */
if (size == off - *bp &&
memcmp(kp, rbufp->page + *bp, size) == 0)
goto found;
off = bp[1];
#ifdef HASH_STATISTICS
hash_collisions++;
#endif
bp += 2;
ndx += 2;
} else if (bp[1] == OVFLPAGE) {
rbufp = __get_buf(hashp, (uint32_t)*bp, rbufp, 0);
if (!rbufp) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
/* FOR LOOP INIT */
bp = (uint16_t *)(void *)rbufp->page;
n = *bp++;
ndx = 1;
off = hashp->BSIZE;
} else if (bp[1] < REAL_KEY) {
if ((ndx =
__find_bigpair(hashp, rbufp, ndx, kp, (int)size)) > 0)
goto found;
if (ndx == -2) {
bufp = rbufp;
if (!(pageno =
__find_last_page(hashp, &bufp))) {
ndx = 0;
rbufp = bufp;
break; /* FOR */
}
rbufp = __get_buf(hashp, (uint32_t)pageno,
bufp, 0);
if (!rbufp) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
/* FOR LOOP INIT */
bp = (uint16_t *)(void *)rbufp->page;
n = *bp++;
ndx = 1;
off = hashp->BSIZE;
} else {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
}
/* Not found */
switch (action) {
case HASH_PUT:
case HASH_PUTNEW:
if (__addel(hashp, rbufp, key, val)) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
} else {
save_bufp->flags &= ~BUF_PIN;
return (SUCCESS);
}
case HASH_GET:
case HASH_DELETE:
default:
save_bufp->flags &= ~BUF_PIN;
return (ABNORMAL);
}
found:
switch (action) {
case HASH_PUTNEW:
save_bufp->flags &= ~BUF_PIN;
return (ABNORMAL);
case HASH_GET:
bp = (uint16_t *)(void *)rbufp->page;
if (bp[ndx + 1] < REAL_KEY) {
if (__big_return(hashp, rbufp, ndx, val, 0))
return (ERROR);
} else {
val->data = (uint8_t *)rbufp->page + (int)bp[ndx + 1];
val->size = bp[ndx] - bp[ndx + 1];
}
break;
case HASH_PUT:
if ((__delpair(hashp, rbufp, ndx)) ||
(__addel(hashp, rbufp, key, val))) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
break;
case HASH_DELETE:
if (__delpair(hashp, rbufp, ndx))
return (ERROR);
break;
default:
abort();
}
save_bufp->flags &= ~BUF_PIN;
return (SUCCESS);
}
static int
hash_seq(const DB *dbp, DBT *key, DBT *data, uint32_t flag)
{
uint32_t bucket;
BUFHEAD *bufp = NULL; /* XXX: gcc */
HTAB *hashp;
uint16_t *bp, ndx;
hashp = dbp->internal;
if (flag && flag != R_FIRST && flag != R_NEXT) {
hashp->err = errno = EINVAL;
return (ERROR);
}
#ifdef HASH_STATISTICS
hash_accesses++;
#endif
if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
hashp->cbucket = 0;
hashp->cndx = 1;
hashp->cpage = NULL;
}
for (bp = NULL; !bp || !bp[0]; ) {
if (!(bufp = hashp->cpage)) {
for (bucket = hashp->cbucket;
bucket <= hashp->MAX_BUCKET;
bucket++, hashp->cndx = 1) {
bufp = __get_buf(hashp, bucket, NULL, 0);
if (!bufp)
return (ERROR);
hashp->cpage = bufp;
bp = (uint16_t *)(void *)bufp->page;
if (bp[0])
break;
}
hashp->cbucket = bucket;
if (hashp->cbucket > hashp->MAX_BUCKET) {
hashp->cbucket = -1;
return (ABNORMAL);
}
} else
bp = (uint16_t *)(void *)hashp->cpage->page;
_DIAGASSERT(bp != NULL);
_DIAGASSERT(bufp != NULL);
while (bp[hashp->cndx + 1] == OVFLPAGE) {
bufp = hashp->cpage =
__get_buf(hashp, (uint32_t)bp[hashp->cndx], bufp,
0);
if (!bufp)
return (ERROR);
bp = (uint16_t *)(void *)(bufp->page);
hashp->cndx = 1;
}
if (!bp[0]) {
hashp->cpage = NULL;
++hashp->cbucket;
}
}
ndx = hashp->cndx;
if (bp[ndx + 1] < REAL_KEY) {
if (__big_keydata(hashp, bufp, key, data, 1))
return (ERROR);
} else {
if (hashp->cpage == NULL)
return (ERROR);
key->data = (uint8_t *)hashp->cpage->page + bp[ndx];
key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
data->data = (uint8_t *)hashp->cpage->page + bp[ndx + 1];
data->size = bp[ndx] - bp[ndx + 1];
ndx += 2;
if (ndx > bp[0]) {
hashp->cpage = NULL;
hashp->cbucket++;
hashp->cndx = 1;
} else
hashp->cndx = ndx;
}
return (SUCCESS);
}
/********************************* UTILITIES ************************/
/*
* Returns:
* 0 ==> OK
* -1 ==> Error
*/
int
__expand_table(HTAB *hashp)
{
uint32_t old_bucket, new_bucket;
int new_segnum, spare_ndx;
size_t dirsize;
#ifdef HASH_STATISTICS
hash_expansions++;
#endif
new_bucket = ++hashp->MAX_BUCKET;
old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
new_segnum = new_bucket >> hashp->SSHIFT;
/* Check if we need a new segment */
if (new_segnum >= hashp->nsegs) {
/* Check if we need to expand directory */
if (new_segnum >= hashp->DSIZE) {
/* Reallocate directory */
dirsize = hashp->DSIZE * sizeof(SEGMENT *);
if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
return (-1);
hashp->DSIZE = dirsize << 1;
}
if ((hashp->dir[new_segnum] =
calloc((size_t)hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
return (-1);
hashp->exsegs++;
hashp->nsegs++;
}
/*
* If the split point is increasing (MAX_BUCKET's log base 2
* * increases), we need to copy the current contents of the spare
* split bucket to the next bucket.
*/
spare_ndx = __log2((uint32_t)(hashp->MAX_BUCKET + 1));
if (spare_ndx > hashp->OVFL_POINT) {
hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
hashp->OVFL_POINT = spare_ndx;
}
if (new_bucket > hashp->HIGH_MASK) {
/* Starting a new doubling */
hashp->LOW_MASK = hashp->HIGH_MASK;
hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
}
/* Relocate records to the new bucket */
return (__split_page(hashp, old_bucket, new_bucket));
}
/*
* If realloc guarantees that the pointer is not destroyed if the realloc
* fails, then this routine can go away.
*/
static void *
hash_realloc(SEGMENT **p_ptr, size_t oldsize, size_t newsize)
{
void *p;
if ((p = malloc(newsize)) != NULL) {
memmove(p, *p_ptr, oldsize);
memset((char *)p + oldsize, 0, newsize - oldsize);
free(*p_ptr);
*p_ptr = p;
}
return (p);
}
uint32_t
__call_hash(HTAB *hashp, char *k, int len)
{
int n, bucket;
n = hashp->hash(k, (size_t)len);
bucket = n & hashp->HIGH_MASK;
if (bucket > hashp->MAX_BUCKET)
bucket = bucket & hashp->LOW_MASK;
return (bucket);
}
/*
* Allocate segment table. On error, destroy the table and set errno.
*
* Returns 0 on success
*/
static int
alloc_segs(HTAB *hashp, int nsegs)
{
int i;
SEGMENT store;
int save_errno;
hashp->dir = calloc((size_t)hashp->DSIZE, sizeof(SEGMENT *));
if (hashp->dir == NULL) {
save_errno = errno;
(void)hdestroy(hashp);
errno = save_errno;
return (-1);
}
hashp->nsegs = nsegs;
if (nsegs == 0)
return 0;
/* Allocate segments */
store = calloc((size_t)(nsegs << hashp->SSHIFT), sizeof(SEGMENT));
if (store == NULL) {
save_errno = errno;
(void)hdestroy(hashp);
errno = save_errno;
return (-1);
}
for (i = 0; i < nsegs; i++)
hashp->dir[i] = &store[i << hashp->SSHIFT];
return (0);
}
#if BYTE_ORDER == LITTLE_ENDIAN
/*
* Hashp->hdr needs to be byteswapped.
*/
static void
swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
{
size_t i;
P_32_COPY(srcp->magic, destp->magic);
P_32_COPY(srcp->version, destp->version);
P_32_COPY(srcp->lorder, destp->lorder);
P_32_COPY(srcp->bsize, destp->bsize);
P_32_COPY(srcp->bshift, destp->bshift);
P_32_COPY(srcp->dsize, destp->dsize);
P_32_COPY(srcp->ssize, destp->ssize);
P_32_COPY(srcp->sshift, destp->sshift);
P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
P_32_COPY(srcp->last_freed, destp->last_freed);
P_32_COPY(srcp->max_bucket, destp->max_bucket);
P_32_COPY(srcp->high_mask, destp->high_mask);
P_32_COPY(srcp->low_mask, destp->low_mask);
P_32_COPY(srcp->ffactor, destp->ffactor);
P_32_COPY(srcp->nkeys, destp->nkeys);
P_32_COPY(srcp->hdrpages, destp->hdrpages);
P_32_COPY(srcp->h_charkey, destp->h_charkey);
for (i = 0; i < NCACHED; i++) {
P_32_COPY(srcp->spares[i], destp->spares[i]);
P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
}
}
static void
swap_header(HTAB *hashp)
{
HASHHDR *hdrp;
size_t i;
hdrp = &hashp->hdr;
M_32_SWAP(hdrp->magic);
M_32_SWAP(hdrp->version);
M_32_SWAP(hdrp->lorder);
M_32_SWAP(hdrp->bsize);
M_32_SWAP(hdrp->bshift);
M_32_SWAP(hdrp->dsize);
M_32_SWAP(hdrp->ssize);
M_32_SWAP(hdrp->sshift);
M_32_SWAP(hdrp->ovfl_point);
M_32_SWAP(hdrp->last_freed);
M_32_SWAP(hdrp->max_bucket);
M_32_SWAP(hdrp->high_mask);
M_32_SWAP(hdrp->low_mask);
M_32_SWAP(hdrp->ffactor);
M_32_SWAP(hdrp->nkeys);
M_32_SWAP(hdrp->hdrpages);
M_32_SWAP(hdrp->h_charkey);
for (i = 0; i < NCACHED; i++) {
M_32_SWAP(hdrp->spares[i]);
M_16_SWAP(hdrp->bitmaps[i]);
}
}
#endif

View File

@@ -0,0 +1,303 @@
/* $NetBSD: hash.h,v 1.3 2010/02/27 16:27:00 joerg Exp $ */
/* NetBSD: hash.h,v 1.15 2008/08/26 21:18:38 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)hash.h 8.3 (Berkeley) 5/31/94
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
/* Operations */
typedef enum {
HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
} ACTION;
/* Buffer Management structures */
typedef struct _bufhead BUFHEAD;
struct _bufhead {
BUFHEAD *prev; /* LRU links */
BUFHEAD *next; /* LRU links */
BUFHEAD *ovfl; /* Overflow page buffer header */
uint32_t addr; /* Address of this page */
char *page; /* Actual page data */
char flags;
#define BUF_MOD 0x0001
#define BUF_DISK 0x0002
#define BUF_BUCKET 0x0004
#define BUF_PIN 0x0008
};
#define IS_BUCKET(X) ((X) & BUF_BUCKET)
typedef BUFHEAD **SEGMENT;
/* Hash Table Information */
typedef struct hashhdr { /* Disk resident portion */
int32_t magic; /* Magic NO for hash tables */
int32_t version; /* Version ID */
uint32_t lorder; /* Byte Order */
int32_t bsize; /* Bucket/Page Size */
int32_t bshift; /* Bucket shift */
int32_t dsize; /* Directory Size */
int32_t ssize; /* Segment Size */
int32_t sshift; /* Segment shift */
int32_t ovfl_point; /* Where overflow pages are being
* allocated */
int32_t last_freed; /* Last overflow page freed */
int32_t max_bucket; /* ID of Maximum bucket in use */
int32_t high_mask; /* Mask to modulo into entire table */
int32_t low_mask; /* Mask to modulo into lower half of
* table */
int32_t ffactor; /* Fill factor */
int32_t nkeys; /* Number of keys in hash table */
int32_t hdrpages; /* Size of table header */
int32_t h_charkey; /* value of hash(CHARKEY) */
#define NCACHED 32 /* number of bit maps and spare
* points */
int32_t spares[NCACHED];/* spare pages for overflow */
uint16_t bitmaps[NCACHED]; /* address of overflow page
* bitmaps */
} HASHHDR;
typedef struct htab { /* Memory resident data structure */
HASHHDR hdr; /* Header */
int nsegs; /* Number of allocated segments */
int exsegs; /* Number of extra allocated
* segments */
uint32_t (*hash)(const void *, size_t); /* Hash function */
int flags; /* Flag values */
int fp; /* File pointer */
char *tmp_buf; /* Temporary Buffer for BIG data */
char *tmp_key; /* Temporary Buffer for BIG keys */
BUFHEAD *cpage; /* Current page */
int cbucket; /* Current bucket */
int cndx; /* Index of next item on cpage */
int err; /* Error Number -- for DBM
* compatibility */
int new_file; /* Indicates if fd is backing store
* or no */
int save_file; /* Indicates whether we need to flush
* file at
* exit */
uint32_t *mapp[NCACHED]; /* Pointers to page maps */
int nmaps; /* Initial number of bitmaps */
int nbufs; /* Number of buffers left to
* allocate */
BUFHEAD bufhead; /* Header of buffer lru list */
SEGMENT *dir; /* Hash Bucket directory */
} HTAB;
/*
* Constants
*/
#define MAX_BSIZE 65536 /* 2^16 */
#define MIN_BUFFERS 6
#define MINHDRSIZE 512
#define DEF_BUFSIZE 65536 /* 64 K */
#define DEF_BUCKET_SIZE 4096
#define DEF_BUCKET_SHIFT 12 /* log2(BUCKET) */
#define DEF_SEGSIZE 256
#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */
#define DEF_DIRSIZE 256
#define DEF_FFACTOR 65536
#define MIN_FFACTOR 4
#define SPLTMAX 8
#define CHARKEY "%$sniglet^&"
#define NUMKEY 1038583
#define BYTE_SHIFT 3
#define INT_TO_BYTE 2
#define INT_BYTE_SHIFT 5
#define ALL_SET ((uint32_t)0xFFFFFFFF)
#define ALL_CLEAR 0
#define PTROF(X) ((BUFHEAD *)(void *)((u_long)(X)&~0x3))
#define ISMOD(X) ((uint32_t)(u_long)(X)&0x1)
#define DOMOD(X) ((X) = (char *)(void *)((u_long)(X)|0x1))
#define ISDISK(X) ((uint32_t)(u_long)(X)&0x2)
#define DODISK(X) ((X) = (char *)(void *)((u_long)(X)|0x2))
#define BITS_PER_MAP 32
/* Given the address of the beginning of a big map, clear/set the nth bit */
#define CLRBIT(A, N) ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
#define SETBIT(A, N) ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
#define ISSET(A, N) ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
/* Overflow management */
/*
* Overflow page numbers are allocated per split point. At each doubling of
* the table, we can allocate extra pages. So, an overflow page number has
* the top 5 bits indicate which split point and the lower 11 bits indicate
* which page at that split point is indicated (pages within split points are
* numberered starting with 1).
*/
#define SPLITSHIFT 11
#define SPLITMASK 0x7FF
#define SPLITNUM(N) (((uint32_t)(N)) >> SPLITSHIFT)
#define OPAGENUM(N) ((N) & SPLITMASK)
#define OADDR_OF(S,O) ((uint32_t)((uint32_t)(S) << SPLITSHIFT) + (O))
#define BUCKET_TO_PAGE(B) \
(B) + hashp->HDRPAGES + \
((B) ? hashp->SPARES[__log2((uint32_t)((B)+1))-1] : 0)
#define OADDR_TO_PAGE(B) \
BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
/*
* page.h contains a detailed description of the page format.
*
* Normally, keys and data are accessed from offset tables in the top of
* each page which point to the beginning of the key and data. There are
* four flag values which may be stored in these offset tables which indicate
* the following:
*
*
* OVFLPAGE Rather than a key data pair, this pair contains
* the address of an overflow page. The format of
* the pair is:
* OVERFLOW_PAGE_NUMBER OVFLPAGE
*
* PARTIAL_KEY This must be the first key/data pair on a page
* and implies that page contains only a partial key.
* That is, the key is too big to fit on a single page
* so it starts on this page and continues on the next.
* The format of the page is:
* KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
*
* KEY_OFF -- offset of the beginning of the key
* PARTIAL_KEY -- 1
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* FULL_KEY This must be the first key/data pair on the page. It
* is used in two cases.
*
* Case 1:
* There is a complete key on the page but no data
* (because it wouldn't fit). The next page contains
* the data.
*
* Page format it:
* KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
*
* KEY_OFF -- offset of the beginning of the key
* FULL_KEY -- 2
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* Case 2:
* This page contains no key, but part of a large
* data field, which is continued on the next page.
*
* Page format it:
* DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
*
* KEY_OFF -- offset of the beginning of the data on
* this page
* FULL_KEY -- 2
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* FULL_KEY_DATA
* This must be the first key/data pair on the page.
* There are two cases:
*
* Case 1:
* This page contains a key and the beginning of the
* data field, but the data field is continued on the
* next page.
*
* Page format is:
* KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
*
* KEY_OFF -- offset of the beginning of the key
* FULL_KEY_DATA -- 3
* OVFL_PAGENO - page number of the next overflow page
* DATA_OFF -- offset of the beginning of the data
*
* Case 2:
* This page contains the last page of a big data pair.
* There is no key, only the tail end of the data
* on this page.
*
* Page format is:
* DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
*
* DATA_OFF -- offset of the beginning of the data on
* this page
* FULL_KEY_DATA -- 3
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* OVFL_PAGENO and OVFLPAGE are optional (they are
* not present if there is no next page).
*/
#define OVFLPAGE 0
#define PARTIAL_KEY 1
#define FULL_KEY 2
#define FULL_KEY_DATA 3
#define REAL_KEY 4
/* Short hands for accessing structure */
#undef BSIZE
#undef BSHIFT
#define BSIZE hdr.bsize
#define BSHIFT hdr.bshift
#define DSIZE hdr.dsize
#define SGSIZE hdr.ssize
#define SSHIFT hdr.sshift
#define LORDER hdr.lorder
#define OVFL_POINT hdr.ovfl_point
#define LAST_FREED hdr.last_freed
#define MAX_BUCKET hdr.max_bucket
#define FFACTOR hdr.ffactor
#define HIGH_MASK hdr.high_mask
#define LOW_MASK hdr.low_mask
#define NKEYS hdr.nkeys
#define HDRPAGES hdr.hdrpages
#define SPARES hdr.spares
#define BITMAPS hdr.bitmaps
#define VERSION hdr.version
#define MAGIC hdr.magic
#define NEXT_FREE hdr.next_free
#define H_CHARKEY hdr.h_charkey
#include <errno.h>
#ifndef EFTYPE
#define EFTYPE EINVAL
#endif

View File

@@ -0,0 +1,673 @@
/* $NetBSD: hash_bigkey.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: hash_bigkey.c,v 1.22 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash_bigkey.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
/*
* PACKAGE: hash
* DESCRIPTION:
* Big key/data handling for the hashing package.
*
* ROUTINES:
* External
* __big_keydata
* __big_split
* __big_insert
* __big_return
* __big_delete
* __find_last_page
* Internal
* collect_key
* collect_data
*/
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static int collect_key(HTAB *, BUFHEAD *, int, DBT *, int);
static int collect_data(HTAB *, BUFHEAD *, int, int);
/*
* Big_insert
*
* You need to do an insert and the key/data pair is too big
*
* Returns:
* 0 ==> OK
*-1 ==> ERROR
*/
int
__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
uint16_t *p;
int key_size, n, val_size;
uint16_t space, move_bytes, off;
char *cp, *key_data, *val_data;
size_t temp;
cp = bufp->page; /* Character pointer of p. */
p = (uint16_t *)(void *)cp;
key_data = (char *)key->data;
_DBFIT(key->size, int);
key_size = (int)key->size;
val_data = (char *)val->data;
_DBFIT(val->size, int);
val_size = (int)val->size;
/* First move the Key */
temp = FREESPACE(p) - BIGOVERHEAD;
_DBFIT(temp, uint16_t);
space = (uint16_t)temp;
while (key_size) {
move_bytes = MIN(space, key_size);
off = OFFSET(p) - move_bytes;
memmove(cp + off, key_data, (size_t)move_bytes);
key_size -= move_bytes;
key_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
temp = off - PAGE_META(n);
_DBFIT(temp, uint16_t);
FREESPACE(p) = (uint16_t)temp;
OFFSET(p) = off;
p[n] = PARTIAL_KEY;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
n = p[0];
if (!key_size) {
space = FREESPACE(p);
if (space) {
move_bytes = MIN(space, val_size);
/*
* If the data would fit exactly in the
* remaining space, we must overflow it to the
* next page; otherwise the invariant that the
* data must end on a page with FREESPACE
* non-zero would fail.
*/
if (space == val_size && val_size == val->size)
goto toolarge;
off = OFFSET(p) - move_bytes;
memmove(cp + off, val_data, (size_t)move_bytes);
val_data += move_bytes;
val_size -= move_bytes;
p[n] = off;
p[n - 2] = FULL_KEY_DATA;
FREESPACE(p) = FREESPACE(p) - move_bytes;
OFFSET(p) = off;
} else {
toolarge:
p[n - 2] = FULL_KEY;
}
}
p = (uint16_t *)(void *)bufp->page;
cp = bufp->page;
bufp->flags |= BUF_MOD;
temp = FREESPACE(p) - BIGOVERHEAD;
_DBFIT(temp, uint16_t);
space = (uint16_t)temp;
}
/* Now move the data */
temp = FREESPACE(p) - BIGOVERHEAD;
_DBFIT(temp, uint16_t);
space = (uint16_t)temp;
while (val_size) {
move_bytes = MIN(space, val_size);
/*
* Here's the hack to make sure that if the data ends on the
* same page as the key ends, FREESPACE is at least one.
*/
if (space == val_size && val_size == val->size)
move_bytes--;
off = OFFSET(p) - move_bytes;
memmove(cp + off, val_data, (size_t)move_bytes);
val_size -= move_bytes;
val_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
temp = off - PAGE_META(n);
_DBFIT(temp, uint16_t);
FREESPACE(p) = (uint16_t)temp;
OFFSET(p) = off;
if (val_size) {
p[n] = FULL_KEY;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
cp = bufp->page;
p = (uint16_t *)(void *)cp;
} else
p[n] = FULL_KEY_DATA;
bufp->flags |= BUF_MOD;
temp = FREESPACE(p) - BIGOVERHEAD;
_DBFIT(temp, uint16_t);
space = (uint16_t)temp;
}
return (0);
}
/*
* Called when bufp's page contains a partial key (index should be 1)
*
* All pages in the big key/data pair except bufp are freed. We cannot
* free bufp because the page pointing to it is lost and we can't get rid
* of its pointer.
*
* Returns:
* 0 => OK
*-1 => ERROR
*/
int
__big_delete(HTAB *hashp, BUFHEAD *bufp)
{
BUFHEAD *last_bfp, *rbufp;
uint16_t *bp, pageno;
int key_done, n;
size_t temp;
rbufp = bufp;
last_bfp = NULL;
bp = (uint16_t *)(void *)bufp->page;
pageno = 0;
key_done = 0;
while (!key_done || (bp[2] != FULL_KEY_DATA)) {
if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA)
key_done = 1;
/*
* If there is freespace left on a FULL_KEY_DATA page, then
* the data is short and fits entirely on this page, and this
* is the last page.
*/
if (bp[2] == FULL_KEY_DATA && FREESPACE(bp))
break;
pageno = bp[bp[0] - 1];
rbufp->flags |= BUF_MOD;
rbufp = __get_buf(hashp, (uint32_t)pageno, rbufp, 0);
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
last_bfp = rbufp;
if (!rbufp)
return (-1); /* Error. */
bp = (uint16_t *)(void *)rbufp->page;
}
/*
* If we get here then rbufp points to the last page of the big
* key/data pair. Bufp points to the first one -- it should now be
* empty pointing to the next page after this pair. Can't free it
* because we don't have the page pointing to it.
*/
/* This is information from the last page of the pair. */
n = bp[0];
pageno = bp[n - 1];
/* Now, bp is the first page of the pair. */
bp = (uint16_t *)(void *)bufp->page;
if (n > 2) {
/* There is an overflow page. */
bp[1] = pageno;
bp[2] = OVFLPAGE;
bufp->ovfl = rbufp->ovfl;
} else
/* This is the last page. */
bufp->ovfl = NULL;
n -= 2;
bp[0] = n;
temp = hashp->BSIZE - PAGE_META(n);
_DBFIT(temp, uint16_t);
FREESPACE(bp) = (uint16_t)temp;
OFFSET(bp) = hashp->BSIZE;
bufp->flags |= BUF_MOD;
if (rbufp)
__free_ovflpage(hashp, rbufp);
if (last_bfp && last_bfp != rbufp)
__free_ovflpage(hashp, last_bfp);
hashp->NKEYS--;
return (0);
}
/*
* Returns:
* 0 = key not found
* -1 = get next overflow page
* -2 means key not found and this is big key/data
* -3 error
*/
int
__find_bigpair(HTAB *hashp, BUFHEAD *bufp, int ndx, char *key, int size)
{
uint16_t *bp;
char *p;
int ksize;
uint16_t bytes;
char *kkey;
bp = (uint16_t *)(void *)bufp->page;
p = bufp->page;
ksize = size;
kkey = key;
for (bytes = hashp->BSIZE - bp[ndx];
bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
bytes = hashp->BSIZE - bp[ndx]) {
if (memcmp(p + bp[ndx], kkey, (size_t)bytes))
return (-2);
kkey += bytes;
ksize -= bytes;
bufp = __get_buf(hashp, (uint32_t)bp[ndx + 2], bufp, 0);
if (!bufp)
return (-3);
p = bufp->page;
bp = (uint16_t *)(void *)p;
ndx = 1;
}
if (bytes != ksize || memcmp(p + bp[ndx], kkey, (size_t)bytes)) {
#ifdef HASH_STATISTICS
++hash_collisions;
#endif
return (-2);
} else
return (ndx);
}
/*
* Given the buffer pointer of the first overflow page of a big pair,
* find the end of the big pair
*
* This will set bpp to the buffer header of the last page of the big pair.
* It will return the pageno of the overflow page following the last page
* of the pair; 0 if there isn't any (i.e. big pair is the last key in the
* bucket)
*/
uint16_t
__find_last_page(HTAB *hashp, BUFHEAD **bpp)
{
BUFHEAD *bufp;
uint16_t *bp, pageno;
int n;
bufp = *bpp;
bp = (uint16_t *)(void *)bufp->page;
for (;;) {
n = bp[0];
/*
* This is the last page if: the tag is FULL_KEY_DATA and
* either only 2 entries OVFLPAGE marker is explicit there
* is freespace on the page.
*/
if (bp[2] == FULL_KEY_DATA &&
((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
break;
pageno = bp[n - 1];
bufp = __get_buf(hashp, (uint32_t)pageno, bufp, 0);
if (!bufp)
return (0); /* Need to indicate an error! */
bp = (uint16_t *)(void *)bufp->page;
}
*bpp = bufp;
if (bp[0] > 2)
return (bp[3]);
else
return (0);
}
/*
* Return the data for the key/data pair that begins on this page at this
* index (index should always be 1).
*/
int
__big_return(HTAB *hashp, BUFHEAD *bufp, int ndx, DBT *val, int set_current)
{
BUFHEAD *save_p;
uint16_t *bp, len, off, save_addr;
char *tp;
bp = (uint16_t *)(void *)bufp->page;
while (bp[ndx + 1] == PARTIAL_KEY) {
bufp = __get_buf(hashp, (uint32_t)bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (uint16_t *)(void *)bufp->page;
ndx = 1;
}
if (bp[ndx + 1] == FULL_KEY) {
bufp = __get_buf(hashp, (uint32_t)bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (uint16_t *)(void *)bufp->page;
save_p = bufp;
save_addr = save_p->addr;
off = bp[1];
len = 0;
} else
if (!FREESPACE(bp)) {
/*
* This is a hack. We can't distinguish between
* FULL_KEY_DATA that contains complete data or
* incomplete data, so we require that if the data
* is complete, there is at least 1 byte of free
* space left.
*/
off = bp[bp[0]];
len = bp[1] - off;
save_p = bufp;
save_addr = bufp->addr;
bufp = __get_buf(hashp, (uint32_t)bp[bp[0] - 1], bufp,
0);
if (!bufp)
return (-1);
bp = (uint16_t *)(void *)bufp->page;
} else {
/* The data is all on one page. */
tp = (char *)(void *)bp;
off = bp[bp[0]];
val->data = (uint8_t *)tp + off;
val->size = bp[1] - off;
if (set_current) {
if (bp[0] == 2) { /* No more buckets in
* chain */
hashp->cpage = NULL;
hashp->cbucket++;
hashp->cndx = 1;
} else {
hashp->cpage = __get_buf(hashp,
(uint32_t)bp[bp[0] - 1], bufp, 0);
if (!hashp->cpage)
return (-1);
hashp->cndx = 1;
if (!((uint16_t *)(void *)
hashp->cpage->page)[0]) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
return (0);
}
val->size = collect_data(hashp, bufp, (int)len, set_current);
if (val->size == (size_t)-1)
return (-1);
if (save_p->addr != save_addr) {
/* We are pretty short on buffers. */
errno = EINVAL; /* OUT OF BUFFERS */
return (-1);
}
memmove(hashp->tmp_buf, (save_p->page) + off, (size_t)len);
val->data = (uint8_t *)hashp->tmp_buf;
return (0);
}
/*
* 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(HTAB *hashp, BUFHEAD *bufp, int len, int set)
{
uint16_t *bp;
char *p;
BUFHEAD *xbp;
uint16_t save_addr;
int mylen, totlen;
p = bufp->page;
bp = (uint16_t *)(void *)p;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
if (bp[2] == FULL_KEY_DATA) { /* End of Data */
totlen = len + mylen;
if (hashp->tmp_buf)
free(hashp->tmp_buf);
if ((hashp->tmp_buf = calloc(1, (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, (uint32_t)bp[bp[0] - 1],
bufp, 0);
if (!hashp->cpage)
return (-1);
else if (!((uint16_t *)(void *)hashp->cpage->page)[0]) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
} else {
xbp = __get_buf(hashp, (uint32_t)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);
}
/*
* Fill in the key and data for this big pair.
*/
int
__big_keydata(HTAB *hashp, BUFHEAD *bufp, DBT *key, DBT *val, int set)
{
key->size = collect_key(hashp, bufp, 0, val, set);
if (key->size == (size_t)-1)
return (-1);
key->data = (uint8_t *)hashp->tmp_key;
return (0);
}
/*
* Count how big the total key size is by recursing through the pages. Then
* collect the data, allocate a buffer and copy the key as you recurse up.
*/
static int
collect_key(HTAB *hashp, BUFHEAD *bufp, int len, DBT *val, int set)
{
BUFHEAD *xbp;
char *p;
int mylen, totlen;
uint16_t *bp, save_addr;
p = bufp->page;
bp = (uint16_t *)(void *)p;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
totlen = len + mylen;
if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */
if (hashp->tmp_key != NULL)
free(hashp->tmp_key);
if ((hashp->tmp_key = calloc(1, (size_t)totlen)) == NULL)
return (-1);
if (__big_return(hashp, bufp, 1, val, set))
return (-1);
} else {
xbp = __get_buf(hashp, (uint32_t)bp[bp[0] - 1], bufp, 0);
if (!xbp || ((totlen =
collect_key(hashp, xbp, totlen, val, set)) < 1))
return (-1);
}
if (bufp->addr != save_addr) {
errno = EINVAL; /* MIS -- OUT OF BUFFERS */
return (-1);
}
memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], (size_t)mylen);
return (totlen);
}
/*
* Returns:
* 0 => OK
* -1 => error
*/
int
__big_split(
HTAB *hashp,
BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */
BUFHEAD *np, /* Pointer to new bucket page */
/* Pointer to first page containing the big key/data */
BUFHEAD *big_keyp,
int addr, /* Address of big_keyp */
uint32_t obucket,/* Old Bucket */
SPLIT_RETURN *ret
)
{
BUFHEAD *tmpp;
uint16_t *tp;
BUFHEAD *bp;
DBT key, val;
uint32_t change;
uint16_t free_space, n, off;
size_t temp;
bp = big_keyp;
/* Now figure out where the big key/data goes */
if (__big_keydata(hashp, big_keyp, &key, &val, 0))
return (-1);
change = (__call_hash(hashp, key.data, (int)key.size) != obucket);
if ((ret->next_addr = __find_last_page(hashp, &big_keyp)) != 0) {
if (!(ret->nextp =
__get_buf(hashp, (uint32_t)ret->next_addr, big_keyp, 0)))
return (-1);
} else
ret->nextp = NULL;
/* Now make one of np/op point to the big key/data pair */
_DIAGASSERT(np->ovfl == NULL);
if (change)
tmpp = np;
else
tmpp = op;
tmpp->flags |= BUF_MOD;
#ifdef DEBUG1
(void)fprintf(stderr,
"BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
(tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
#endif
tmpp->ovfl = bp; /* one of op/np point to big_keyp */
tp = (uint16_t *)(void *)tmpp->page;
_DIAGASSERT(FREESPACE(tp) >= OVFLSIZE);
n = tp[0];
off = OFFSET(tp);
free_space = FREESPACE(tp);
tp[++n] = (uint16_t)addr;
tp[++n] = OVFLPAGE;
tp[0] = n;
OFFSET(tp) = off;
temp = free_space - OVFLSIZE;
_DBFIT(temp, uint16_t);
FREESPACE(tp) = (uint16_t)temp;
/*
* Finally, set the new and old return values. BIG_KEYP contains a
* pointer to the last page of the big key_data pair. Make sure that
* big_keyp has no following page (2 elements) or create an empty
* following page.
*/
ret->newp = np;
ret->oldp = op;
tp = (uint16_t *)(void *)big_keyp->page;
big_keyp->flags |= BUF_MOD;
if (tp[0] > 2) {
/*
* There may be either one or two offsets on this page. If
* there is one, then the overflow page is linked on normally
* and tp[4] is OVFLPAGE. If there are two, tp[4] contains
* the second offset and needs to get stuffed in after the
* next overflow page is added.
*/
n = tp[4];
free_space = FREESPACE(tp);
off = OFFSET(tp);
tp[0] -= 2;
temp = free_space + OVFLSIZE;
_DBFIT(temp, uint16_t);
FREESPACE(tp) = (uint16_t)temp;
OFFSET(tp) = off;
tmpp = __add_ovflpage(hashp, big_keyp);
if (!tmpp)
return (-1);
tp[4] = n;
} else
tmpp = big_keyp;
if (change)
ret->newp = tmpp;
else
ret->oldp = tmpp;
return (0);
}

View File

@@ -0,0 +1,334 @@
/* $NetBSD: hash_buf.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: hash_buf.c,v 1.14 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash_buf.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
/*
* PACKAGE: hash
*
* DESCRIPTION:
* Contains buffer management
*
* ROUTINES:
* External
* __buf_init
* __get_buf
* __buf_free
* __reclaim_buf
* Internal
* newbuf
*/
#include <sys/param.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static BUFHEAD *newbuf(HTAB *, uint32_t, BUFHEAD *);
/* Unlink B from its place in the lru */
#define BUF_REMOVE(B) { \
(B)->prev->next = (B)->next; \
(B)->next->prev = (B)->prev; \
}
/* Insert B after P */
#define BUF_INSERT(B, P) { \
(B)->next = (P)->next; \
(B)->prev = (P); \
(P)->next = (B); \
(B)->next->prev = (B); \
}
#define MRU hashp->bufhead.next
#define LRU hashp->bufhead.prev
#define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
#define LRU_INSERT(B) BUF_INSERT((B), LRU)
/*
* We are looking for a buffer with address "addr". If prev_bp is NULL, then
* address is a bucket index. If prev_bp is not NULL, then it points to the
* page previous to an overflow page that we are trying to find.
*
* CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
* be valid. Therefore, you must always verify that its address matches the
* address you are seeking.
*/
BUFHEAD *
__get_buf(
HTAB *hashp,
uint32_t addr,
BUFHEAD *prev_bp,
int newpage /* If prev_bp set, indicates a new overflow page. */
)
{
BUFHEAD *bp;
uint32_t is_disk_mask;
int is_disk, segment_ndx = 0; /* pacify gcc */
SEGMENT segp = NULL; /* pacify gcc */
is_disk = 0;
is_disk_mask = 0;
if (prev_bp) {
bp = prev_bp->ovfl;
if (!bp || (bp->addr != addr))
bp = NULL;
if (!newpage)
is_disk = BUF_DISK;
} else {
/* Grab buffer out of directory */
segment_ndx = addr & (hashp->SGSIZE - 1);
/* valid segment ensured by __call_hash() */
segp = hashp->dir[addr >> hashp->SSHIFT];
_DIAGASSERT(segp != NULL);
bp = PTROF(segp[segment_ndx]);
is_disk_mask = ISDISK(segp[segment_ndx]);
is_disk = is_disk_mask || !hashp->new_file;
}
if (!bp) {
bp = newbuf(hashp, addr, prev_bp);
if (!bp ||
__get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
return (NULL);
if (!prev_bp)
segp[segment_ndx] =
(BUFHEAD *)(void *)((u_long)bp | is_disk_mask);
} else {
BUF_REMOVE(bp);
MRU_INSERT(bp);
}
return (bp);
}
/*
* We need a buffer for this page. Either allocate one, or evict a resident
* one (if we have as many buffers as we're allowed) and put this one in.
*
* If newbuf finds an error (returning NULL), it also sets errno.
*/
static BUFHEAD *
newbuf(HTAB *hashp, uint32_t addr, BUFHEAD *prev_bp)
{
BUFHEAD *bp; /* The buffer we're going to use */
BUFHEAD *xbp; /* Temp pointer */
BUFHEAD *next_xbp;
SEGMENT segp;
int segment_ndx;
uint16_t oaddr, *shortp;
oaddr = 0;
bp = LRU;
/*
* If LRU buffer is pinned, the buffer pool is too small. We need to
* allocate more buffers.
*/
if (hashp->nbufs || (bp->flags & BUF_PIN)) {
/* Allocate a new one */
if ((bp = calloc(1, sizeof(BUFHEAD))) == NULL)
return (NULL);
if ((bp->page = calloc(1, (size_t)hashp->BSIZE)) == NULL) {
free(bp);
return (NULL);
}
if (hashp->nbufs)
hashp->nbufs--;
} else {
/* Kick someone out */
BUF_REMOVE(bp);
/*
* If this is an overflow page with addr 0, it's already been
* flushed back in an overflow chain and initialized.
*/
if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
/*
* Set oaddr before __put_page so that you get it
* before bytes are swapped.
*/
shortp = (uint16_t *)(void *)bp->page;
if (shortp[0])
oaddr = shortp[shortp[0] - 1];
if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
bp->addr, (int)IS_BUCKET(bp->flags), 0))
return (NULL);
/*
* Update the pointer to this page (i.e. invalidate it).
*
* If this is a new file (i.e. we created it at open
* time), make sure that we mark pages which have been
* written to disk so we retrieve them from disk later,
* rather than allocating new pages.
*/
if (IS_BUCKET(bp->flags)) {
segment_ndx = bp->addr & (hashp->SGSIZE - 1);
segp = hashp->dir[bp->addr >> hashp->SSHIFT];
_DIAGASSERT(segp != NULL);
if (hashp->new_file &&
((bp->flags & BUF_MOD) ||
ISDISK(segp[segment_ndx])))
segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
else
segp[segment_ndx] = NULL;
}
/*
* Since overflow pages can only be access by means of
* their bucket, free overflow pages associated with
* this bucket.
*/
for (xbp = bp; xbp->ovfl;) {
next_xbp = xbp->ovfl;
xbp->ovfl = 0;
xbp = next_xbp;
/* Check that ovfl pointer is up date. */
if (IS_BUCKET(xbp->flags) ||
(oaddr != xbp->addr))
break;
shortp = (uint16_t *)(void *)xbp->page;
if (shortp[0])
/* set before __put_page */
oaddr = shortp[shortp[0] - 1];
if ((xbp->flags & BUF_MOD) && __put_page(hashp,
xbp->page, xbp->addr, 0, 0))
return (NULL);
xbp->addr = 0;
xbp->flags = 0;
BUF_REMOVE(xbp);
LRU_INSERT(xbp);
}
}
}
/* Now assign this buffer */
bp->addr = addr;
#ifdef DEBUG1
(void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
#endif
bp->ovfl = NULL;
if (prev_bp) {
/*
* If prev_bp is set, this is an overflow page, hook it in to
* the buffer overflow links.
*/
#ifdef DEBUG1
(void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0),
(bp ? bp->addr : 0));
#endif
prev_bp->ovfl = bp;
bp->flags = 0;
} else
bp->flags = BUF_BUCKET;
MRU_INSERT(bp);
return (bp);
}
void
__buf_init(HTAB *hashp, u_int nbytes)
{
BUFHEAD *bfp;
int npages;
bfp = &(hashp->bufhead);
npages = (unsigned int)(nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
npages = MAX(npages, MIN_BUFFERS);
hashp->nbufs = npages;
bfp->next = bfp;
bfp->prev = bfp;
/*
* This space is calloc'd so these are already null.
*
* bfp->ovfl = NULL;
* bfp->flags = 0;
* bfp->page = NULL;
* bfp->addr = 0;
*/
}
int
__buf_free(HTAB *hashp, int do_free, int to_disk)
{
BUFHEAD *bp;
/* Need to make sure that buffer manager has been initialized */
if (!LRU)
return (0);
for (bp = LRU; bp != &hashp->bufhead;) {
/* Check that the buffer is valid */
if (bp->addr || IS_BUCKET(bp->flags)) {
if (to_disk && (bp->flags & BUF_MOD) &&
__put_page(hashp, bp->page,
bp->addr, IS_BUCKET(bp->flags), 0))
return (-1);
}
/* Check if we are freeing stuff */
if (do_free) {
if (bp->page)
free(bp->page);
BUF_REMOVE(bp);
free(bp);
bp = LRU;
} else
bp = bp->prev;
}
return (0);
}
void
__reclaim_buf(HTAB *hashp, BUFHEAD *bp)
{
bp->ovfl = 0;
bp->addr = 0;
bp->flags = 0;
BUF_REMOVE(bp);
LRU_INSERT(bp);
}

View File

@@ -0,0 +1,207 @@
/* $NetBSD: hash_func.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: hash_func.c,v 1.13 2008/09/10 17:52:35 joerg Exp */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash_func.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
#if 0
static uint32_t hash1(const void *, size_t) __attribute__((__unused__));
static uint32_t hash2(const void *, size_t) __attribute__((__unused__));
static uint32_t hash3(const void *, size_t) __attribute__((__unused__));
#endif
static uint32_t hash4(const void *, size_t) __attribute__((__unused__));
/* Global default hash function */
uint32_t (*__default_hash)(const void *, size_t) = hash4;
#if 0
/*
* HASH FUNCTIONS
*
* Assume that we've already split the bucket to which this key hashes,
* calculate that bucket, and check that in fact we did already split it.
*
* This came from ejb's hsearch.
*/
#define PRIME1 37
#define PRIME2 1048583
static uint32_t
hash1(const void *keyarg, size_t len)
{
const uint8_t *key;
uint32_t h;
/* Convert string to integer */
for (key = keyarg, h = 0; len--;)
h = h * PRIME1 ^ (*key++ - ' ');
h %= PRIME2;
return (h);
}
/*
* Phong's linear congruential hash
*/
#define dcharhash(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
static uint32_t
hash2(const void *keyarg, size_t len)
{
const uint8_t *e, *key;
uint32_t h;
uint8_t c;
key = keyarg;
e = key + len;
for (h = 0; key != e;) {
c = *key++;
if (!c && key > e)
break;
dcharhash(h, c);
}
return (h);
}
/*
* This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
* units. On the first time through the loop we get the "leftover bytes"
* (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
* all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
* this routine is heavily used enough, it's worth the ugly coding.
*
* OZ's original sdbm hash
*/
static uint32_t
hash3(const void *keyarg, size_t len)
{
const uint8_t *key;
size_t loop;
uint32_t h;
#define HASHC h = *key++ + 65599 * h
h = 0;
key = keyarg;
if (len > 0) {
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do {
HASHC;
/* FALLTHROUGH */
case 7:
HASHC;
/* FALLTHROUGH */
case 6:
HASHC;
/* FALLTHROUGH */
case 5:
HASHC;
/* FALLTHROUGH */
case 4:
HASHC;
/* FALLTHROUGH */
case 3:
HASHC;
/* FALLTHROUGH */
case 2:
HASHC;
/* FALLTHROUGH */
case 1:
HASHC;
} while (--loop);
}
}
return (h);
}
#endif
/* Hash function from Chris Torek. */
static uint32_t
hash4(const void *keyarg, size_t len)
{
const uint8_t *key;
size_t loop;
uint32_t h;
#define HASH4a h = (h << 5) - h + *key++;
#define HASH4b h = (h << 5) + h + *key++;
#define HASH4 HASH4b
h = 0;
key = keyarg;
if (len > 0) {
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do {
HASH4;
/* FALLTHROUGH */
case 7:
HASH4;
/* FALLTHROUGH */
case 6:
HASH4;
/* FALLTHROUGH */
case 5:
HASH4;
/* FALLTHROUGH */
case 4:
HASH4;
/* FALLTHROUGH */
case 3:
HASH4;
/* FALLTHROUGH */
case 2:
HASH4;
/* FALLTHROUGH */
case 1:
HASH4;
} while (--loop);
}
}
return (h);
}

View File

@@ -0,0 +1,61 @@
/* $NetBSD: hash_log2.c,v 1.1 2008/10/10 00:21:43 joerg Exp $ */
/* NetBSD: hash_log2.c,v 1.13 2008/09/11 12:33:55 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash_log2.c,v 1.1 2008/10/10 00:21:43 joerg Exp $");
#include <sys/types.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
uint32_t
__log2(uint32_t num)
{
uint32_t i, limit;
if (num == 0)
return 0;
--num;
limit = 0;
for (i = 0; limit < num; limit = limit * 2 + 1, i++)
continue;
return (i);
}

View File

@@ -0,0 +1,972 @@
/* $NetBSD: hash_page.c,v 1.6 2010/04/20 00:32:23 joerg Exp $ */
/* NetBSD: hash_page.c,v 1.23 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: hash_page.c,v 1.6 2010/04/20 00:32:23 joerg Exp $");
/*
* PACKAGE: hashing
*
* DESCRIPTION:
* Page manipulation for hashing package.
*
* ROUTINES:
*
* External
* __get_page
* __add_ovflpage
* Internal
* overflow_page
* open_temp
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nbcompat/paths.h>
#include <assert.h>
#include <nbcompat/db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
#ifdef BROKEN_PREAD
#include "../pread.c"
#endif
#ifdef BROKEN_PWRITE
#include "../pwrite.c"
#endif
static uint32_t *fetch_bitmap(HTAB *, int);
static uint32_t first_free(uint32_t);
static int open_temp(HTAB *);
static uint16_t overflow_page(HTAB *);
static void putpair(char *, const DBT *, const DBT *);
static void squeeze_key(uint16_t *, const DBT *, const DBT *);
static int ugly_split(HTAB *, uint32_t, BUFHEAD *, BUFHEAD *, int, int);
#define PAGE_INIT(P) { \
((uint16_t *)(void *)(P))[0] = 0; \
temp = 3 * sizeof(uint16_t); \
_DIAGASSERT(hashp->BSIZE >= temp); \
((uint16_t *)(void *)(P))[1] = (uint16_t)(hashp->BSIZE - temp); \
((uint16_t *)(void *)(P))[2] = hashp->BSIZE; \
}
/*
* This is called AFTER we have verified that there is room on the page for
* the pair (PAIRFITS has returned true) so we go right ahead and start moving
* stuff on.
*/
static void
putpair(char *p, const DBT *key, const DBT *val)
{
uint16_t *bp, n, off;
size_t temp;
bp = (uint16_t *)(void *)p;
/* Enter the key first. */
n = bp[0];
temp = OFFSET(bp);
_DIAGASSERT(temp >= key->size);
off = (uint16_t)(temp - key->size);
memmove(p + off, key->data, key->size);
bp[++n] = off;
/* Now the data. */
_DIAGASSERT(off >= val->size);
off -= (uint16_t)val->size;
memmove(p + off, val->data, val->size);
bp[++n] = off;
/* Adjust page info. */
bp[0] = n;
temp = (n + 3) * sizeof(uint16_t);
_DIAGASSERT(off >= temp);
bp[n + 1] = (uint16_t)(off - temp);
bp[n + 2] = off;
}
/*
* Returns:
* 0 OK
* -1 error
*/
int
__delpair(HTAB *hashp, BUFHEAD *bufp, int ndx)
{
uint16_t *bp, newoff;
int n;
uint16_t pairlen;
size_t temp;
bp = (uint16_t *)(void *)bufp->page;
n = bp[0];
if (bp[ndx + 1] < REAL_KEY)
return (__big_delete(hashp, bufp));
if (ndx != 1)
newoff = bp[ndx - 1];
else
newoff = hashp->BSIZE;
pairlen = newoff - bp[ndx + 1];
if (ndx != (n - 1)) {
/* Hard Case -- need to shuffle keys */
int i;
char *src = bufp->page + (int)OFFSET(bp);
char *dst = src + (int)pairlen;
memmove(dst, src, (size_t)(bp[ndx + 1] - OFFSET(bp)));
/* Now adjust the pointers */
for (i = ndx + 2; i <= n; i += 2) {
if (bp[i + 1] == OVFLPAGE) {
bp[i - 2] = bp[i];
bp[i - 1] = bp[i + 1];
} else {
bp[i - 2] = bp[i] + pairlen;
bp[i - 1] = bp[i + 1] + pairlen;
}
}
}
/* Finally adjust the page data */
bp[n] = OFFSET(bp) + pairlen;
temp = bp[n + 1] + pairlen + 2 * sizeof(uint16_t);
_DIAGASSERT(temp <= 0xffff);
bp[n - 1] = (uint16_t)temp;
bp[0] = n - 2;
hashp->NKEYS--;
bufp->flags |= BUF_MOD;
return (0);
}
/*
* Returns:
* 0 ==> OK
* -1 ==> Error
*/
int
__split_page(HTAB *hashp, uint32_t obucket, uint32_t nbucket)
{
BUFHEAD *new_bufp, *old_bufp;
uint16_t *ino;
char *np;
DBT key, val;
int n, ndx, retval;
uint16_t copyto, diff, off, moved;
char *op;
size_t temp;
copyto = (uint16_t)hashp->BSIZE;
off = (uint16_t)hashp->BSIZE;
old_bufp = __get_buf(hashp, obucket, NULL, 0);
if (old_bufp == NULL)
return (-1);
new_bufp = __get_buf(hashp, nbucket, NULL, 0);
if (new_bufp == NULL)
return (-1);
old_bufp->flags |= (BUF_MOD | BUF_PIN);
new_bufp->flags |= (BUF_MOD | BUF_PIN);
ino = (uint16_t *)(void *)(op = old_bufp->page);
np = new_bufp->page;
moved = 0;
for (n = 1, ndx = 1; n < ino[0]; n += 2) {
if (ino[n + 1] < REAL_KEY) {
retval = ugly_split(hashp, obucket, old_bufp, new_bufp,
(int)copyto, (int)moved);
old_bufp->flags &= ~BUF_PIN;
new_bufp->flags &= ~BUF_PIN;
return (retval);
}
key.data = (uint8_t *)op + ino[n];
key.size = off - ino[n];
if (__call_hash(hashp, key.data, (int)key.size) == obucket) {
/* Don't switch page */
diff = copyto - off;
if (diff) {
copyto = ino[n + 1] + diff;
memmove(op + copyto, op + ino[n + 1],
(size_t)(off - ino[n + 1]));
ino[ndx] = copyto + ino[n] - ino[n + 1];
ino[ndx + 1] = copyto;
} else
copyto = ino[n + 1];
ndx += 2;
} else {
/* Switch page */
val.data = (uint8_t *)op + ino[n + 1];
val.size = ino[n] - ino[n + 1];
putpair(np, &key, &val);
moved += 2;
}
off = ino[n + 1];
}
/* Now clean up the page */
ino[0] -= moved;
temp = sizeof(uint16_t) * (ino[0] + 3);
_DIAGASSERT(copyto >= temp);
FREESPACE(ino) = (uint16_t)(copyto - temp);
OFFSET(ino) = copyto;
#ifdef DEBUG3
(void)fprintf(stderr, "split %d/%d\n",
((uint16_t *)np)[0] / 2,
((uint16_t *)op)[0] / 2);
#endif
/* unpin both pages */
old_bufp->flags &= ~BUF_PIN;
new_bufp->flags &= ~BUF_PIN;
return (0);
}
/*
* Called when we encounter an overflow or big key/data page during split
* handling. This is special cased since we have to begin checking whether
* the key/data pairs fit on their respective pages and because we may need
* overflow pages for both the old and new pages.
*
* The first page might be a page with regular key/data pairs in which case
* we have a regular overflow condition and just need to go on to the next
* page or it might be a big key/data pair in which case we need to fix the
* big key/data pair.
*
* Returns:
* 0 ==> success
* -1 ==> failure
*/
static int
ugly_split(
HTAB *hashp,
uint32_t obucket, /* Same as __split_page. */
BUFHEAD *old_bufp,
BUFHEAD *new_bufp,
int copyto, /* First byte on page which contains key/data values. */
int moved /* Number of pairs moved to new page. */
)
{
BUFHEAD *bufp; /* Buffer header for ino */
uint16_t *ino; /* Page keys come off of */
uint16_t *np; /* New page */
uint16_t *op; /* Page keys go on to if they aren't moving */
size_t temp;
BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
DBT key, val;
SPLIT_RETURN ret;
uint16_t n, off, ov_addr, scopyto;
char *cino; /* Character value of ino */
bufp = old_bufp;
ino = (uint16_t *)(void *)old_bufp->page;
np = (uint16_t *)(void *)new_bufp->page;
op = (uint16_t *)(void *)old_bufp->page;
last_bfp = NULL;
scopyto = (uint16_t)copyto; /* ANSI */
n = ino[0] - 1;
while (n < ino[0]) {
if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
if (__big_split(hashp, old_bufp,
new_bufp, bufp, (int)bufp->addr, obucket, &ret))
return (-1);
old_bufp = ret.oldp;
if (!old_bufp)
return (-1);
op = (uint16_t *)(void *)old_bufp->page;
new_bufp = ret.newp;
if (!new_bufp)
return (-1);
np = (uint16_t *)(void *)new_bufp->page;
bufp = ret.nextp;
if (!bufp)
return (0);
cino = (char *)bufp->page;
ino = (uint16_t *)(void *)cino;
last_bfp = ret.nextp;
} else if (ino[n + 1] == OVFLPAGE) {
ov_addr = ino[n];
/*
* Fix up the old page -- the extra 2 are the fields
* which contained the overflow information.
*/
ino[0] -= (moved + 2);
temp = sizeof(uint16_t) * (ino[0] + 3);
_DIAGASSERT(scopyto >= temp);
FREESPACE(ino) = (uint16_t)(scopyto - temp);
OFFSET(ino) = scopyto;
bufp = __get_buf(hashp, (uint32_t)ov_addr, bufp, 0);
if (!bufp)
return (-1);
ino = (uint16_t *)(void *)bufp->page;
n = 1;
scopyto = hashp->BSIZE;
moved = 0;
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
last_bfp = bufp;
}
/* Move regular sized pairs of there are any */
off = hashp->BSIZE;
for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
cino = (char *)(void *)ino;
key.data = (uint8_t *)cino + ino[n];
key.size = off - ino[n];
val.data = (uint8_t *)cino + ino[n + 1];
val.size = ino[n] - ino[n + 1];
off = ino[n + 1];
if (__call_hash(hashp, key.data, (int)key.size) == obucket) {
/* Keep on old page */
if (PAIRFITS(op, (&key), (&val)))
putpair((char *)(void *)op, &key, &val);
else {
old_bufp =
__add_ovflpage(hashp, old_bufp);
if (!old_bufp)
return (-1);
op = (uint16_t *)(void *)old_bufp->page;
putpair((char *)(void *)op, &key, &val);
}
old_bufp->flags |= BUF_MOD;
} else {
/* Move to new page */
if (PAIRFITS(np, (&key), (&val)))
putpair((char *)(void *)np, &key, &val);
else {
new_bufp =
__add_ovflpage(hashp, new_bufp);
if (!new_bufp)
return (-1);
np = (uint16_t *)(void *)new_bufp->page;
putpair((char *)(void *)np, &key, &val);
}
new_bufp->flags |= BUF_MOD;
}
}
}
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
return (0);
}
/*
* Add the given pair to the page
*
* Returns:
* 0 ==> OK
* 1 ==> failure
*/
int
__addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
uint16_t *bp, *sop;
int do_expand;
bp = (uint16_t *)(void *)bufp->page;
do_expand = 0;
while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
/* Exception case */
if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
/* This is the last page of a big key/data pair
and we need to add another page */
break;
else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
bufp = __get_buf(hashp, (uint32_t)bp[bp[0] - 1], bufp,
0);
if (!bufp)
return (-1);
bp = (uint16_t *)(void *)bufp->page;
} else if (bp[bp[0]] != OVFLPAGE) {
/* Short key/data pairs, no more pages */
break;
} else {
/* Try to squeeze key on this page */
if (bp[2] >= REAL_KEY &&
FREESPACE(bp) >= PAIRSIZE(key, val)) {
squeeze_key(bp, key, val);
goto stats;
} else {
bufp = __get_buf(hashp,
(uint32_t)bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (uint16_t *)(void *)bufp->page;
}
}
if (PAIRFITS(bp, key, val))
putpair(bufp->page, key, val);
else {
do_expand = 1;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
sop = (uint16_t *)(void *)bufp->page;
if (PAIRFITS(sop, key, val))
putpair((char *)(void *)sop, key, val);
else
if (__big_insert(hashp, bufp, key, val))
return (-1);
}
stats:
bufp->flags |= BUF_MOD;
/*
* If the average number of keys per bucket exceeds the fill factor,
* expand the table.
*/
hashp->NKEYS++;
if (do_expand ||
(hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
return (__expand_table(hashp));
return (0);
}
/*
*
* Returns:
* pointer on success
* NULL on error
*/
BUFHEAD *
__add_ovflpage(HTAB *hashp, BUFHEAD *bufp)
{
uint16_t *sp;
uint16_t ndx, ovfl_num;
size_t temp;
#ifdef DEBUG1
int tmp1, tmp2;
#endif
sp = (uint16_t *)(void *)bufp->page;
/* Check if we are dynamically determining the fill factor */
if (hashp->FFACTOR == DEF_FFACTOR) {
hashp->FFACTOR = (uint32_t)sp[0] >> 1;
if (hashp->FFACTOR < MIN_FFACTOR)
hashp->FFACTOR = MIN_FFACTOR;
}
bufp->flags |= BUF_MOD;
ovfl_num = overflow_page(hashp);
#ifdef DEBUG1
tmp1 = bufp->addr;
tmp2 = bufp->ovfl ? bufp->ovfl->addr : 0;
#endif
if (!ovfl_num || !(bufp->ovfl = __get_buf(hashp, (uint32_t)ovfl_num,
bufp, 1)))
return (NULL);
bufp->ovfl->flags |= BUF_MOD;
#ifdef DEBUG1
(void)fprintf(stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n",
tmp1, tmp2, bufp->ovfl->addr);
#endif
ndx = sp[0];
/*
* Since a pair is allocated on a page only if there's room to add
* an overflow page, we know that the OVFL information will fit on
* the page.
*/
sp[ndx + 4] = OFFSET(sp);
temp = FREESPACE(sp);
_DIAGASSERT(temp >= OVFLSIZE);
sp[ndx + 3] = (uint16_t)(temp - OVFLSIZE);
sp[ndx + 1] = ovfl_num;
sp[ndx + 2] = OVFLPAGE;
sp[0] = ndx + 2;
#ifdef HASH_STATISTICS
hash_overflows++;
#endif
return (bufp->ovfl);
}
/*
* Returns:
* 0 indicates SUCCESS
* -1 indicates FAILURE
*/
int
__get_page(HTAB *hashp, char *p, uint32_t bucket, int is_bucket, int is_disk,
int is_bitmap)
{
int fd, page, size;
ssize_t rsize;
uint16_t *bp;
size_t temp;
fd = hashp->fp;
size = hashp->BSIZE;
if ((fd == -1) || !is_disk) {
PAGE_INIT(p);
return (0);
}
if (is_bucket)
page = BUCKET_TO_PAGE(bucket);
else
page = OADDR_TO_PAGE(bucket);
if ((rsize = pread(fd, p, (size_t)size, (off_t)page << hashp->BSHIFT)) == -1)
return (-1);
bp = (uint16_t *)(void *)p;
if (!rsize)
bp[0] = 0; /* We hit the EOF, so initialize a new page */
else
if (rsize != size) {
errno = EFTYPE;
return (-1);
}
if (!is_bitmap && !bp[0]) {
PAGE_INIT(p);
} else
if (hashp->LORDER != BYTE_ORDER) {
int i, max;
if (is_bitmap) {
max = (uint32_t)hashp->BSIZE >> 2; /* divide by 4 */
for (i = 0; i < max; i++)
M_32_SWAP(((int *)(void *)p)[i]);
} else {
M_16_SWAP(bp[0]);
max = bp[0] + 2;
for (i = 1; i <= max; i++)
M_16_SWAP(bp[i]);
}
}
return (0);
}
/*
* Write page p to disk
*
* Returns:
* 0 ==> OK
* -1 ==>failure
*/
int
__put_page(HTAB *hashp, char *p, uint32_t bucket, int is_bucket, int is_bitmap)
{
int fd, page, size;
ssize_t wsize;
size = hashp->BSIZE;
if ((hashp->fp == -1) && open_temp(hashp))
return (-1);
fd = hashp->fp;
if (hashp->LORDER != BYTE_ORDER) {
int i;
int max;
if (is_bitmap) {
max = (uint32_t)hashp->BSIZE >> 2; /* divide by 4 */
for (i = 0; i < max; i++)
M_32_SWAP(((int *)(void *)p)[i]);
} else {
max = ((uint16_t *)(void *)p)[0] + 2;
for (i = 0; i <= max; i++)
M_16_SWAP(((uint16_t *)(void *)p)[i]);
}
}
if (is_bucket)
page = BUCKET_TO_PAGE(bucket);
else
page = OADDR_TO_PAGE(bucket);
if ((wsize = pwrite(fd, p, (size_t)size, (off_t)page << hashp->BSHIFT)) == -1)
/* Errno is set */
return (-1);
if (wsize != size) {
errno = EFTYPE;
return (-1);
}
return (0);
}
#define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1)
/*
* Initialize a new bitmap page. Bitmap pages are left in memory
* once they are read in.
*/
int
__ibitmap(HTAB *hashp, int pnum, int nbits, int ndx)
{
uint32_t *ip;
int clearbytes, clearints;
if ((ip = malloc((size_t)hashp->BSIZE)) == NULL)
return (1);
hashp->nmaps++;
clearints = ((uint32_t)(nbits - 1) >> INT_BYTE_SHIFT) + 1;
clearbytes = clearints << INT_TO_BYTE;
(void)memset(ip, 0, (size_t)clearbytes);
(void)memset(((char *)(void *)ip) + clearbytes, 0xFF,
(size_t)(hashp->BSIZE - clearbytes));
ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
SETBIT(ip, 0);
hashp->BITMAPS[ndx] = (uint16_t)pnum;
hashp->mapp[ndx] = ip;
return (0);
}
static uint32_t
first_free(uint32_t map)
{
uint32_t i, mask;
mask = 0x1;
for (i = 0; i < BITS_PER_MAP; i++) {
if (!(mask & map))
return (i);
mask = mask << 1;
}
return (i);
}
static uint16_t
overflow_page(HTAB *hashp)
{
uint32_t *freep = NULL;
int max_free, offset, splitnum;
uint16_t addr;
int bit, first_page, free_bit, free_page, i, in_use_bits, j;
#ifdef DEBUG2
int tmp1, tmp2;
#endif
splitnum = hashp->OVFL_POINT;
max_free = hashp->SPARES[splitnum];
free_page = (uint32_t)(max_free - 1) >> (hashp->BSHIFT + BYTE_SHIFT);
free_bit = (max_free - 1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
/* Look through all the free maps to find the first free block */
first_page = (uint32_t)hashp->LAST_FREED >>(hashp->BSHIFT + BYTE_SHIFT);
for ( i = first_page; i <= free_page; i++ ) {
if (!(freep = (uint32_t *)hashp->mapp[i]) &&
!(freep = fetch_bitmap(hashp, i)))
return (0);
if (i == free_page)
in_use_bits = free_bit;
else
in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1;
if (i == first_page) {
bit = hashp->LAST_FREED &
((hashp->BSIZE << BYTE_SHIFT) - 1);
j = bit / BITS_PER_MAP;
bit = bit & ~(BITS_PER_MAP - 1);
} else {
bit = 0;
j = 0;
}
for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
if (freep[j] != ALL_SET)
goto found;
}
/* No Free Page Found */
hashp->LAST_FREED = hashp->SPARES[splitnum];
hashp->SPARES[splitnum]++;
offset = hashp->SPARES[splitnum] -
(splitnum ? hashp->SPARES[splitnum - 1] : 0);
#define OVMSG "HASH: Out of overflow pages. Increase page size\n"
if (offset > SPLITMASK) {
if (++splitnum >= NCACHED) {
(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
hashp->OVFL_POINT = splitnum;
hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
hashp->SPARES[splitnum-1]--;
offset = 1;
}
/* Check if we need to allocate a new bitmap page */
if (free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1) {
free_page++;
if (free_page >= NCACHED) {
(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
/*
* This is tricky. The 1 indicates that you want the new page
* allocated with 1 clear bit. Actually, you are going to
* allocate 2 pages from this map. The first is going to be
* the map page, the second is the overflow page we were
* looking for. The init_bitmap routine automatically, sets
* the first bit of itself to indicate that the bitmap itself
* is in use. We would explicitly set the second bit, but
* don't have to if we tell init_bitmap not to leave it clear
* in the first place.
*/
if (__ibitmap(hashp,
(int)OADDR_OF(splitnum, offset), 1, free_page))
return (0);
hashp->SPARES[splitnum]++;
#ifdef DEBUG2
free_bit = 2;
#endif
offset++;
if (offset > SPLITMASK) {
if (++splitnum >= NCACHED) {
(void)write(STDERR_FILENO, OVMSG,
sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
hashp->OVFL_POINT = splitnum;
hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
hashp->SPARES[splitnum-1]--;
offset = 0;
}
} else {
/*
* Free_bit addresses the last used bit. Bump it to address
* the first available bit.
*/
free_bit++;
SETBIT(freep, free_bit);
}
/* Calculate address of the new overflow page */
addr = OADDR_OF(splitnum, offset);
#ifdef DEBUG2
(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
addr, free_bit, free_page);
#endif
return (addr);
found:
bit = bit + first_free(freep[j]);
SETBIT(freep, bit);
#ifdef DEBUG2
tmp1 = bit;
tmp2 = i;
#endif
/*
* Bits are addressed starting with 0, but overflow pages are addressed
* beginning at 1. Bit is a bit addressnumber, so we need to increment
* it to convert it to a page number.
*/
bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
if (bit >= hashp->LAST_FREED)
hashp->LAST_FREED = bit - 1;
/* Calculate the split number for this page */
for (i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++);
offset = (i ? bit - hashp->SPARES[i - 1] : bit);
if (offset >= SPLITMASK) {
(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0); /* Out of overflow pages */
}
addr = OADDR_OF(i, offset);
#ifdef DEBUG2
(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
addr, tmp1, tmp2);
#endif
/* Allocate and return the overflow page */
return (addr);
}
/*
* Mark this overflow page as free.
*/
void
__free_ovflpage(HTAB *hashp, BUFHEAD *obufp)
{
uint16_t addr;
uint32_t *freep;
int bit_address, free_page, free_bit;
uint16_t ndx;
addr = obufp->addr;
#ifdef DEBUG1
(void)fprintf(stderr, "Freeing %d\n", addr);
#endif
ndx = (((uint32_t)addr) >> SPLITSHIFT);
bit_address =
(ndx ? hashp->SPARES[ndx - 1] : 0) + (addr & SPLITMASK) - 1;
if (bit_address < hashp->LAST_FREED)
hashp->LAST_FREED = bit_address;
free_page = ((uint32_t)bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
if (!(freep = hashp->mapp[free_page]))
freep = fetch_bitmap(hashp, free_page);
/*
* This had better never happen. It means we tried to read a bitmap
* that has already had overflow pages allocated off it, and we
* failed to read it from the file.
*/
_DIAGASSERT(freep != NULL);
CLRBIT(freep, free_bit);
#ifdef DEBUG2
(void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
obufp->addr, free_bit, free_page);
#endif
__reclaim_buf(hashp, obufp);
}
/*
* Returns:
* 0 success
* -1 failure
*/
static int
open_temp(HTAB *hashp)
{
sigset_t set, oset;
char *envtmp;
#ifdef PATH_MAX
char namestr[PATH_MAX];
#else
char namestr[MAXPATHLEN];
#endif
#if HAVE_ISSETUGID
if (issetugid())
envtmp = NULL;
else
#endif
envtmp = getenv("TMPDIR");
if (-1 == snprintf(namestr, sizeof(namestr), "%s/_hashXXXXXX",
envtmp ? envtmp : _PATH_TMP))
return -1;
/* Block signals; make sure file goes away at process exit. */
(void)sigfillset(&set);
(void)sigprocmask(SIG_BLOCK, &set, &oset);
if ((hashp->fp = mkstemp(namestr)) != -1) {
(void)unlink(namestr);
(void)fcntl(hashp->fp, F_SETFD, FD_CLOEXEC);
}
(void)sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
return (hashp->fp != -1 ? 0 : -1);
}
/*
* We have to know that the key will fit, but the last entry on the page is
* an overflow pair, so we need to shift things.
*/
static void
squeeze_key(uint16_t *sp, const DBT *key, const DBT *val)
{
char *p;
uint16_t free_space, n, off, pageno;
size_t temp;
p = (char *)(void *)sp;
n = sp[0];
free_space = FREESPACE(sp);
off = OFFSET(sp);
pageno = sp[n - 1];
_DIAGASSERT(off >= key->size);
off -= (uint16_t)key->size;
sp[n - 1] = off;
memmove(p + off, key->data, key->size);
_DIAGASSERT(off >= val->size);
off -= (uint16_t)val->size;
sp[n] = off;
memmove(p + off, val->data, val->size);
sp[0] = n + 2;
sp[n + 1] = pageno;
sp[n + 2] = OVFLPAGE;
temp = PAIRSIZE(key, val);
_DIAGASSERT(free_space >= temp);
FREESPACE(sp) = (uint16_t)(free_space - temp);
OFFSET(sp) = off;
}
static uint32_t *
fetch_bitmap(HTAB *hashp, int ndx)
{
if (ndx >= hashp->nmaps)
return (NULL);
if ((hashp->mapp[ndx] = malloc((size_t)hashp->BSIZE)) == NULL)
return (NULL);
if (__get_page(hashp,
(char *)(void *)hashp->mapp[ndx], (uint32_t)hashp->BITMAPS[ndx], 0, 1, 1)) {
free(hashp->mapp[ndx]);
return (NULL);
}
return (hashp->mapp[ndx]);
}
#ifdef DEBUG4
void print_chain(HTAB *, uint32_t);
void
print_chain(HTAB *hashp, uint32_t addr)
{
BUFHEAD *bufp;
uint16_t *bp, oaddr;
(void)fprintf(stderr, "%d ", addr);
bufp = __get_buf(hashp, addr, NULL, 0);
bp = (uint16_t *)bufp->page;
while (bp[0] && ((bp[bp[0]] == OVFLPAGE) ||
((bp[0] > 2) && bp[2] < REAL_KEY))) {
oaddr = bp[bp[0] - 1];
(void)fprintf(stderr, "%d ", (int)oaddr);
bufp = __get_buf(hashp, (uint32_t)oaddr, bufp, 0);
bp = (uint16_t *)bufp->page;
}
(void)fprintf(stderr, "\n");
}
#endif

View File

@@ -0,0 +1,112 @@
/* $NetBSD: ndbm.c,v 1.2 2008/10/29 11:23:17 joerg Exp $ */
/* NetBSD: ndbm.c,v 1.23 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: ndbm.c,v 1.2 2008/10/29 11:23:17 joerg Exp $");
/*
* This package provides a dbm compatible interface to the new hashing
* package described in db(3).
*/
#include <nbcompat/param.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <nbcompat/ndbm.h>
#include "hash.h"
/*
* Returns:
* *DBM on success
* NULL on failure
*/
DBM *
dbm_open(const char *file, int flags, mode_t mode)
{
HASHINFO info;
char path[MAXPATHLEN];
info.bsize = 4096;
info.ffactor = 40;
info.nelem = 1;
info.cachesize = 0;
info.hash = NULL;
info.lorder = 0;
(void)strncpy(path, file, sizeof(path) - 1);
(void)strncat(path, DBM_SUFFIX, sizeof(path) - strlen(path) - 1);
if ((flags & O_ACCMODE) == O_WRONLY) {
flags &= ~O_WRONLY;
flags |= O_RDWR;
}
return ((DBM *)__hash_open(path, flags, mode, &info, 0));
}
void
dbm_close(DBM *db)
{
(void)(db->close)(db);
}
int
dbm_error(DBM *db)
{
HTAB *hp;
hp = db->internal;
return (hp->err);
}
int
dbm_clearerr(DBM *db)
{
HTAB *hp;
hp = db->internal;
hp->err = 0;
return (0);
}
int
dbm_dirfno(DBM *db)
{
HTAB *hp;
hp = db->internal;
return hp->fp;
}

View File

@@ -0,0 +1,155 @@
/* $NetBSD: ndbmdatum.c,v 1.2 2008/10/29 11:23:17 joerg Exp $ */
/* NetBSD: ndbmdatum.c,v 1.4 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: ndbmdatum.c,v 1.2 2008/10/29 11:23:17 joerg Exp $");
/*
* This package provides a dbm compatible interface to the new hashing
* package described in db(3).
*/
#include <nbcompat/param.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <nbcompat/ndbm.h>
#include "hash.h"
/*
* Returns:
* DATUM on success
* NULL on failure
*/
datum
dbm_fetch(DBM *db, datum key)
{
datum retdata;
int status;
DBT dbtkey, dbtretdata;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
status = (db->get)(db, &dbtkey, &dbtretdata, 0);
if (status) {
dbtretdata.data = NULL;
dbtretdata.size = 0;
}
retdata.dptr = dbtretdata.data;
retdata.dsize = dbtretdata.size;
return (retdata);
}
/*
* Returns:
* DATUM on success
* NULL on failure
*/
datum
dbm_firstkey(DBM *db)
{
int status;
datum retkey;
DBT dbtretkey, dbtretdata;
status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST);
if (status)
dbtretkey.data = NULL;
retkey.dptr = dbtretkey.data;
retkey.dsize = dbtretkey.size;
return (retkey);
}
/*
* Returns:
* DATUM on success
* NULL on failure
*/
datum
dbm_nextkey(DBM *db)
{
int status;
datum retkey;
DBT dbtretkey, dbtretdata;
status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT);
if (status)
dbtretkey.data = NULL;
retkey.dptr = dbtretkey.data;
retkey.dsize = dbtretkey.size;
return (retkey);
}
/*
* Returns:
* 0 on success
* <0 failure
*/
int
dbm_delete(DBM *db, datum key)
{
int status;
DBT dbtkey;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
status = (db->del)(db, &dbtkey, 0);
if (status)
return (-1);
else
return (0);
}
/*
* Returns:
* 0 on success
* <0 failure
* 1 if DBM_INSERT and entry exists
*/
int
dbm_store(DBM *db, datum key, datum data, int flags)
{
DBT dbtkey, dbtdata;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
dbtdata.data = data.dptr;
dbtdata.size = data.dsize;
return ((db->put)(db, &dbtkey, &dbtdata,
(u_int)((flags == DBM_INSERT) ? R_NOOVERWRITE : 0)));
}

View File

@@ -0,0 +1,91 @@
/* $NetBSD: page.h,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: page.h,v 1.8 2008/08/26 21:18:38 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)page.h 8.2 (Berkeley) 5/31/94
*/
/*
* Definitions for hashing page file format.
*/
/*
* routines dealing with a data page
*
* page format:
* +------------------------------+
* p | n | keyoff | datoff | keyoff |
* +------------+--------+--------+
* | datoff | free | ptr | --> |
* +--------+---------------------+
* | F R E E A R E A |
* +--------------+---------------+
* | <---- - - - | data |
* +--------+-----+----+----------+
* | key | data | key |
* +--------+----------+----------+
*
* Pointer to the free space is always: p[p[0] + 2]
* Amount of free space on the page is: p[p[0] + 1]
*/
/*
* How many bytes required for this pair?
* 2 shorts in the table at the top of the page + room for the
* key and room for the data
*
* We prohibit entering a pair on a page unless there is also room to append
* an overflow page. The reason for this it that you can get in a situation
* where a single key/data pair fits on a page, but you can't append an
* overflow page and later you'd have to split the key/data and handle like
* a big pair.
* You might as well do this up front.
*/
#define PAIRSIZE(K,D) (2*sizeof(uint16_t) + (K)->size + (D)->size)
#define BIGOVERHEAD (4*sizeof(uint16_t))
#define KEYSIZE(K) (4*sizeof(uint16_t) + (K)->size);
#define OVFLSIZE (2*sizeof(uint16_t))
#define FREESPACE(P) ((P)[(P)[0]+1])
#define OFFSET(P) ((P)[(P)[0]+2])
#define PAIRFITS(P,K,D) \
(((P)[2] >= REAL_KEY) && \
(PAIRSIZE((K),(D)) + OVFLSIZE) <= FREESPACE((P)))
#define PAGE_META(N) (((N)+3) * sizeof(uint16_t))
typedef struct {
BUFHEAD *newp;
BUFHEAD *oldp;
BUFHEAD *nextp;
uint16_t next_addr;
} SPLIT_RETURN;

View File

@@ -0,0 +1,473 @@
/* $NetBSD: mpool.c,v 1.5 2010/04/20 00:32:23 joerg Exp $ */
/* NetBSD: mpool.c,v 1.18 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: mpool.c,v 1.5 2010/04/20 00:32:23 joerg Exp $");
#include <nbcompat/queue.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nbcompat/db.h>
#define __MPOOLINTERFACE_PRIVATE
#include <nbcompat/mpool.h>
#ifndef EFTYPE
#define EFTYPE EINVAL
#endif
#if 0
#ifdef __weak_alias
__weak_alias(mpool_close,_mpool_close)
__weak_alias(mpool_filter,_mpool_filter)
__weak_alias(mpool_get,_mpool_get)
__weak_alias(mpool_new,_mpool_new)
__weak_alias(mpool_open,_mpool_open)
__weak_alias(mpool_put,_mpool_put)
__weak_alias(mpool_sync,_mpool_sync)
#endif
#endif
static BKT *mpool_bkt(MPOOL *);
static BKT *mpool_look(MPOOL *, pgno_t);
static int mpool_write(MPOOL *, BKT *);
#ifdef BROKEN_PREAD
#include "../pread.c"
#endif
#ifdef BROKEN_PWRITE
#include "../pwrite.c"
#endif
/*
* mpool_open --
* Initialize a memory pool.
*/
/*ARGSUSED*/
MPOOL *
mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
{
struct stat sb;
MPOOL *mp;
int entry;
/*
* Get information about the file.
*
* XXX
* We don't currently handle pipes, although we should.
*/
if (fstat(fd, &sb))
return (NULL);
if (!S_ISREG(sb.st_mode)) {
errno = ESPIPE;
return (NULL);
}
/* Allocate and initialize the MPOOL cookie. */
if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
return (NULL);
CIRCLEQ_INIT(&mp->lqh);
for (entry = 0; entry < HASHSIZE; ++entry)
CIRCLEQ_INIT(&mp->hqh[entry]);
mp->maxcache = maxcache;
mp->npages = (pgno_t)(sb.st_size / pagesize);
mp->pagesize = pagesize;
mp->fd = fd;
return (mp);
}
/*
* mpool_filter --
* Initialize input/output filters.
*/
void
mpool_filter(MPOOL *mp, void (*pgin)(void *, pgno_t, void *),
void (*pgout)(void *, pgno_t, void *), void *pgcookie)
{
mp->pgin = pgin;
mp->pgout = pgout;
mp->pgcookie = pgcookie;
}
/*
* mpool_new --
* Get a new page of memory.
*/
void *
mpool_new( MPOOL *mp, pgno_t *pgnoaddr)
{
struct _hqh *head;
BKT *bp;
if (mp->npages == MAX_PAGE_NUMBER) {
(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
abort();
}
#ifdef STATISTICS
++mp->pagenew;
#endif
/*
* Get a BKT from the cache. Assign a new page number, attach
* it to the head of the hash chain, the tail of the lru chain,
* and return.
*/
if ((bp = mpool_bkt(mp)) == NULL)
return (NULL);
*pgnoaddr = bp->pgno = mp->npages++;
bp->flags = MPOOL_PINNED;
head = &mp->hqh[HASHKEY(bp->pgno)];
CIRCLEQ_INSERT_HEAD(head, bp, hq);
CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
return (bp->page);
}
/*
* mpool_get
* Get a page.
*/
/*ARGSUSED*/
void *
mpool_get(MPOOL *mp, pgno_t pgno, u_int flags)
{
struct _hqh *head;
BKT *bp;
off_t off;
ssize_t nr;
/* Check for attempt to retrieve a non-existent page. */
if (pgno >= mp->npages) {
errno = EINVAL;
return (NULL);
}
#ifdef STATISTICS
++mp->pageget;
#endif
/* Check for a page that is cached. */
if ((bp = mpool_look(mp, pgno)) != NULL) {
#ifdef DEBUG
if (bp->flags & MPOOL_PINNED) {
(void)fprintf(stderr,
"mpool_get: page %d already pinned\n", bp->pgno);
abort();
}
#endif
/*
* Move the page to the head of the hash chain and the tail
* of the lru chain.
*/
head = &mp->hqh[HASHKEY(bp->pgno)];
CIRCLEQ_REMOVE(head, bp, hq);
CIRCLEQ_INSERT_HEAD(head, bp, hq);
CIRCLEQ_REMOVE(&mp->lqh, bp, q);
CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
/* Return a pinned page. */
bp->flags |= MPOOL_PINNED;
return (bp->page);
}
/* Get a page from the cache. */
if ((bp = mpool_bkt(mp)) == NULL)
return (NULL);
/* Read in the contents. */
#ifdef STATISTICS
++mp->pageread;
#endif
off = mp->pagesize * pgno;
if ((nr = pread(mp->fd, bp->page, (size_t)mp->pagesize, off)) != (int)mp->pagesize) {
if (nr >= 0)
errno = EFTYPE;
return (NULL);
}
/* Set the page number, pin the page. */
bp->pgno = pgno;
bp->flags = MPOOL_PINNED;
/*
* Add the page to the head of the hash chain and the tail
* of the lru chain.
*/
head = &mp->hqh[HASHKEY(bp->pgno)];
CIRCLEQ_INSERT_HEAD(head, bp, hq);
CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
/* Run through the user's filter. */
if (mp->pgin != NULL)
(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
return (bp->page);
}
/*
* mpool_put
* Return a page.
*/
/*ARGSUSED*/
int
mpool_put(MPOOL *mp, void *page, u_int flags)
{
BKT *bp;
#ifdef STATISTICS
++mp->pageput;
#endif
bp = (BKT *)(void *)((char *)page - sizeof(BKT));
#ifdef DEBUG
if (!(bp->flags & MPOOL_PINNED)) {
(void)fprintf(stderr,
"mpool_put: page %d not pinned\n", bp->pgno);
abort();
}
#endif
bp->flags &= ~MPOOL_PINNED;
bp->flags |= flags & MPOOL_DIRTY;
return (RET_SUCCESS);
}
/*
* mpool_close
* Close the buffer pool.
*/
int
mpool_close(MPOOL *mp)
{
BKT *bp;
/* Free up any space allocated to the lru pages. */
while ((bp = mp->lqh.cqh_first) != (void *)&mp->lqh) {
CIRCLEQ_REMOVE(&mp->lqh, mp->lqh.cqh_first, q);
free(bp);
}
/* Free the MPOOL cookie. */
free(mp);
return (RET_SUCCESS);
}
/*
* mpool_sync
* Sync the pool to disk.
*/
int
mpool_sync(MPOOL *mp)
{
BKT *bp;
/* Walk the lru chain, flushing any dirty pages to disk. */
for (bp = mp->lqh.cqh_first;
bp != (void *)&mp->lqh; bp = bp->q.cqe_next)
if (bp->flags & MPOOL_DIRTY &&
mpool_write(mp, bp) == RET_ERROR)
return (RET_ERROR);
/* Sync the file descriptor. */
return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
}
/*
* mpool_bkt
* Get a page from the cache (or create one).
*/
static BKT *
mpool_bkt(MPOOL *mp)
{
struct _hqh *head;
BKT *bp;
/* If under the max cached, always create a new page. */
if (mp->curcache < mp->maxcache)
goto new;
/*
* If the cache is max'd out, walk the lru list for a buffer we
* can flush. If we find one, write it (if necessary) and take it
* off any lists. If we don't find anything we grow the cache anyway.
* The cache never shrinks.
*/
for (bp = mp->lqh.cqh_first;
bp != (void *)&mp->lqh; bp = bp->q.cqe_next)
if (!(bp->flags & MPOOL_PINNED)) {
/* Flush if dirty. */
if (bp->flags & MPOOL_DIRTY &&
mpool_write(mp, bp) == RET_ERROR)
return (NULL);
#ifdef STATISTICS
++mp->pageflush;
#endif
/* Remove from the hash and lru queues. */
head = &mp->hqh[HASHKEY(bp->pgno)];
CIRCLEQ_REMOVE(head, bp, hq);
CIRCLEQ_REMOVE(&mp->lqh, bp, q);
#ifdef DEBUG
{
void *spage = bp->page;
(void)memset(bp, 0xff,
(size_t)(sizeof(BKT) + mp->pagesize));
bp->page = spage;
}
#endif
return (bp);
}
new: if ((bp = (BKT *)malloc((size_t)(sizeof(BKT) + mp->pagesize))) == NULL)
return (NULL);
#ifdef STATISTICS
++mp->pagealloc;
#endif
#if defined(DEBUG) || defined(PURIFY)
(void)memset(bp, 0xff, (size_t)(sizeof(BKT) + mp->pagesize));
#endif
bp->page = (char *)(void *)bp + sizeof(BKT);
++mp->curcache;
return (bp);
}
/*
* mpool_write
* Write a page to disk.
*/
static int
mpool_write(MPOOL *mp, BKT *bp)
{
off_t off;
#ifdef STATISTICS
++mp->pagewrite;
#endif
/* Run through the user's filter. */
if (mp->pgout)
(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
off = mp->pagesize * bp->pgno;
if (pwrite(mp->fd, bp->page, (size_t)mp->pagesize, off) != (int)mp->pagesize)
return (RET_ERROR);
/*
* Re-run through the input filter since this page may soon be
* accessed via the cache, and whatever the user's output filter
* did may screw things up if we don't let the input filter
* restore the in-core copy.
*/
if (mp->pgin)
(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
bp->flags &= ~MPOOL_DIRTY;
return (RET_SUCCESS);
}
/*
* mpool_look
* Lookup a page in the cache.
*/
static BKT *
mpool_look(MPOOL *mp, pgno_t pgno)
{
struct _hqh *head;
BKT *bp;
head = &mp->hqh[HASHKEY(pgno)];
for (bp = head->cqh_first; bp != (void *)head; bp = bp->hq.cqe_next)
if (bp->pgno == pgno) {
#ifdef STATISTICS
++mp->cachehit;
#endif
return (bp);
}
#ifdef STATISTICS
++mp->cachemiss;
#endif
return (NULL);
}
#ifdef STATISTICS
/*
* mpool_stat
* Print out cache statistics.
*/
void
mpool_stat(mp)
MPOOL *mp;
{
BKT *bp;
int cnt;
const char *sep;
(void)fprintf(stderr, "%lu pages in the file\n", (u_long)mp->npages);
(void)fprintf(stderr,
"page size %lu, cacheing %lu pages of %lu page max cache\n",
(u_long)mp->pagesize, (u_long)mp->curcache, (u_long)mp->maxcache);
(void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
mp->pageput, mp->pageget, mp->pagenew);
(void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
mp->pagealloc, mp->pageflush);
if (mp->cachehit + mp->cachemiss)
(void)fprintf(stderr,
"%.0f%% cache hit rate (%lu hits, %lu misses)\n",
((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
* 100, mp->cachehit, mp->cachemiss);
(void)fprintf(stderr, "%lu page reads, %lu page writes\n",
mp->pageread, mp->pagewrite);
sep = "";
cnt = 0;
for (bp = mp->lqh.cqh_first;
bp != (void *)&mp->lqh; bp = bp->q.cqe_next) {
(void)fprintf(stderr, "%s%d", sep, bp->pgno);
if (bp->flags & MPOOL_DIRTY)
(void)fprintf(stderr, "d");
if (bp->flags & MPOOL_PINNED)
(void)fprintf(stderr, "P");
if (++cnt == 10) {
sep = "\n";
cnt = 0;
} else
sep = ", ";
}
(void)fprintf(stderr, "\n");
}
#endif

View File

@@ -0,0 +1,12 @@
/* $NetBSD: pread.c,v 1.1 2010/04/20 00:32:22 joerg Exp $ */
static ssize_t
working_pread(int fd, void *buf, size_t nbytes, off_t off)
{
if (lseek(fd, off, SEEK_SET) == -1)
return -1;
return read(fd, buf, nbytes);
}
#undef pread
#define pread(fd, buf, nbytes, off) working_pread(fd, buf, nbytes,off)

View File

@@ -0,0 +1,12 @@
/* $NetBSD: pwrite.c,v 1.1 2010/04/20 00:32:23 joerg Exp $ */
static ssize_t
working_pwrite(int fd, const void *buf, size_t nbytes, off_t off)
{
if (lseek(fd, off, SEEK_SET) == -1)
return -1;
return write(fd, buf, nbytes);
}
#undef pwrite
#define pwrite(fd, buf, nbytes, off) working_pwrite(fd, buf, nbytes,off)

View File

@@ -0,0 +1,53 @@
/* $NetBSD: extern.h,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: extern.h,v 1.8 2008/08/26 21:18:38 joerg Exp */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.3 (Berkeley) 6/4/94
*/
#include "../btree/extern.h"
int __rec_close(DB *);
int __rec_delete(const DB *, const DBT *, u_int);
int __rec_dleaf(BTREE *, PAGE *, uint32_t);
int __rec_fd(const DB *);
int __rec_fmap(BTREE *, recno_t);
int __rec_fout(BTREE *);
int __rec_fpipe(BTREE *, recno_t);
int __rec_get(const DB *, const DBT *, DBT *, u_int);
int __rec_iput(BTREE *, recno_t, const DBT *, u_int);
int __rec_put(const DB *dbp, DBT *, const DBT *, u_int);
int __rec_ret(BTREE *, EPG *, recno_t, DBT *, DBT *);
EPG *__rec_search(BTREE *, recno_t, enum SRCHOP);
int __rec_seq(const DB *, DBT *, DBT *, u_int);
int __rec_sync(const DB *, u_int);
int __rec_vmap(BTREE *, recno_t);
int __rec_vout(BTREE *);
int __rec_vpipe(BTREE *, recno_t);

View File

@@ -0,0 +1,184 @@
/* $NetBSD: rec_close.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_close.c,v 1.15 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_close.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __REC_CLOSE -- Close a recno tree.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_close(DB *dbp)
{
BTREE *t;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
if (__rec_sync(dbp, 0) == RET_ERROR)
return (RET_ERROR);
/* Committed to closing. */
status = RET_SUCCESS;
if (F_ISSET(t, R_MEMMAPPED) && munmap(t->bt_smap, t->bt_msize))
status = RET_ERROR;
if (!F_ISSET(t, R_INMEM)) {
if (F_ISSET(t, R_CLOSEFP)) {
if (fclose(t->bt_rfp))
status = RET_ERROR;
} else {
if (close(t->bt_rfd))
status = RET_ERROR;
}
}
if (__bt_close(dbp) == RET_ERROR)
status = RET_ERROR;
return (status);
}
/*
* __REC_SYNC -- sync the recno tree to disk.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_sync(const DB *dbp, u_int flags)
{
struct iovec iov[2];
BTREE *t;
DBT data, key;
off_t off;
recno_t scursor, trec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
if (flags == R_RECNOSYNC)
return (__bt_sync(dbp, 0));
if (F_ISSET(t, R_RDONLY | R_INMEM) || !F_ISSET(t, R_MODIFIED))
return (RET_SUCCESS);
/* Read any remaining records into the tree. */
if (!F_ISSET(t, R_EOF) && t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
return (RET_ERROR);
/* Rewind the file descriptor. */
if (lseek(t->bt_rfd, (off_t)0, SEEK_SET) != 0)
return (RET_ERROR);
/* Save the cursor. */
scursor = t->bt_cursor.rcursor;
key.size = sizeof(recno_t);
key.data = &trec;
if (F_ISSET(t, R_FIXLEN)) {
/*
* We assume that fixed length records are all fixed length.
* Any that aren't are either EINVAL'd or corrected by the
* record put code.
*/
status = (dbp->seq)(dbp, &key, &data, R_FIRST);
while (status == RET_SUCCESS) {
if (write(t->bt_rfd, data.data, data.size) !=
(ssize_t) data.size)
return (RET_ERROR);
status = (dbp->seq)(dbp, &key, &data, R_NEXT);
}
} else {
iov[1].iov_base = &t->bt_bval;
iov[1].iov_len = 1;
status = (dbp->seq)(dbp, &key, &data, R_FIRST);
while (status == RET_SUCCESS) {
iov[0].iov_base = data.data;
iov[0].iov_len = data.size;
if (writev(t->bt_rfd, iov, 2) !=
(ssize_t) (data.size + 1))
return (RET_ERROR);
status = (dbp->seq)(dbp, &key, &data, R_NEXT);
}
}
/* Restore the cursor. */
t->bt_cursor.rcursor = scursor;
if (status == RET_ERROR)
return (RET_ERROR);
if ((off = lseek(t->bt_rfd, (off_t)0, SEEK_CUR)) == -1)
return (RET_ERROR);
if (ftruncate(t->bt_rfd, off))
return (RET_ERROR);
F_CLR(t, R_MODIFIED);
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,195 @@
/* $NetBSD: rec_delete.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_delete.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_delete.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <nbcompat/db.h>
#include "recno.h"
static int rec_rdelete(BTREE *, recno_t);
/*
* __REC_DELETE -- Delete the item(s) referenced by a key.
*
* Parameters:
* dbp: pointer to access method
* key: key to delete
* flags: R_CURSOR if deleting what the cursor references
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__rec_delete(const DB *dbp, const DBT *key, u_int flags)
{
BTREE *t;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
switch(flags) {
case 0:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
if (nrec > t->bt_nrecs)
return (RET_SPECIAL);
--nrec;
status = rec_rdelete(t, nrec);
break;
case R_CURSOR:
if (!F_ISSET(&t->bt_cursor, CURS_INIT))
goto einval;
if (t->bt_nrecs == 0)
return (RET_SPECIAL);
status = rec_rdelete(t, t->bt_cursor.rcursor - 1);
if (status == RET_SUCCESS)
--t->bt_cursor.rcursor;
break;
default:
einval: errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS)
F_SET(t, B_MODIFIED | R_MODIFIED);
return (status);
}
/*
* REC_RDELETE -- Delete the data matching the specified key.
*
* Parameters:
* tree: tree
* nrec: record to delete
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
static int
rec_rdelete(BTREE *t, recno_t nrec)
{
EPG *e;
PAGE *h;
int status;
/* Find the record; __rec_search pins the page. */
if ((e = __rec_search(t, nrec, SDELETE)) == NULL)
return (RET_ERROR);
/* Delete the record. */
h = e->page;
status = __rec_dleaf(t, h, (uint32_t)e->index);
if (status != RET_SUCCESS) {
mpool_put(t->bt_mp, h, 0);
return (status);
}
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* __REC_DLEAF -- Delete a single record from a recno leaf page.
*
* Parameters:
* t: tree
* index: index on current page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_dleaf(BTREE *t, PAGE *h, uint32_t idx)
{
RLEAF *rl;
indx_t *ip, cnt, offset;
uint32_t nbytes;
char *from;
void *to;
size_t temp;
/*
* Delete a record from a recno leaf page. Internal records are never
* deleted from internal pages, regardless of the records that caused
* them to be added being deleted. Pages made empty by deletion are
* not reclaimed. They are, however, made available for reuse.
*
* Pack the remaining entries at the end of the page, shift the indices
* down, overwriting the deleted record and its index. If the record
* uses overflow pages, make them available for reuse.
*/
to = rl = GETRLEAF(h, idx);
if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
return (RET_ERROR);
nbytes = NRLEAF(rl);
/*
* Compress the key/data pairs. Compress and adjust the [BR]LEAF
* offsets. Reset the headers.
*/
from = (char *)(void *)h + h->upper;
memmove(from + nbytes, from, (size_t)((char *)to - from));
h->upper += nbytes;
offset = h->linp[idx];
temp = &h->linp[idx] - (ip = &h->linp[0]);
_DBFIT(temp, uint16_t);
for (cnt = (uint16_t)temp; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nbytes;
temp = &h->linp[NEXTINDEX(h)] - ip;
_DBFIT(temp, uint16_t);
for (cnt = (uint16_t)temp; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
h->lower -= sizeof(indx_t);
--t->bt_nrecs;
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,300 @@
/* $NetBSD: rec_get.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_get.c,v 1.16 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_get.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __REC_GET -- Get a record from the btree.
*
* Parameters:
* dbp: pointer to access method
* key: key to find
* data: data to return
* flag: currently unused
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__rec_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG *e;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Get currently doesn't take any flags, and keys of 0 are illegal. */
if (flags || (nrec = *(recno_t *)key->data) == 0) {
errno = EINVAL;
return (RET_ERROR);
}
/*
* If we haven't seen this record yet, try to find it in the
* original file.
*/
if (nrec > t->bt_nrecs) {
if (F_ISSET(t, R_EOF | R_INMEM))
return (RET_SPECIAL);
if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
return (status);
}
--nrec;
if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
return (RET_ERROR);
status = __rec_ret(t, e, 0, NULL, data);
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e->page, 0);
else
t->bt_pinned = e->page;
return (status);
}
/*
* __REC_FPIPE -- Get fixed length records from a pipe.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_fpipe(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
size_t len;
int ch;
uint8_t *p;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data = t->bt_rdata.data == NULL ?
malloc(t->bt_reclen) :
realloc(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
data.data = t->bt_rdata.data;
data.size = t->bt_reclen;
for (nrec = t->bt_nrecs; nrec < top;) {
len = t->bt_reclen;
for (p = t->bt_rdata.data;; *p++ = ch)
if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
if (ch != EOF)
*p = ch;
if (len != 0)
memset(p, t->bt_bval, len);
if (__rec_iput(t,
nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
++nrec;
break;
}
if (ch == EOF)
break;
}
if (nrec < top) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
return (RET_SUCCESS);
}
/*
* __REC_VPIPE -- Get variable length records from a pipe.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_vpipe(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
ptrdiff_t len;
size_t sz;
int bval, ch;
uint8_t *p;
bval = t->bt_bval;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
for (p = t->bt_rdata.data,
sz = t->bt_rdata.size;; *p++ = ch, --sz) {
if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
data.data = t->bt_rdata.data;
data.size = p - (uint8_t *)t->bt_rdata.data;
if (ch == EOF && data.size == 0)
break;
if (__rec_iput(t, nrec, &data, 0)
!= RET_SUCCESS)
return (RET_ERROR);
break;
}
if (sz == 0) {
len = p - (uint8_t *)t->bt_rdata.data;
t->bt_rdata.size += (sz = 256);
t->bt_rdata.data = t->bt_rdata.data == NULL ?
malloc(t->bt_rdata.size) :
realloc(t->bt_rdata.data, t->bt_rdata.size);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
p = (uint8_t *)t->bt_rdata.data + len;
}
}
if (ch == EOF)
break;
}
if (nrec < top) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
return (RET_SUCCESS);
}
/*
* __REC_FMAP -- Get fixed length records from a file.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_fmap(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
uint8_t *sp, *ep, *p;
size_t len;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data = t->bt_rdata.data == NULL ?
malloc(t->bt_reclen) :
realloc(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
data.data = t->bt_rdata.data;
data.size = t->bt_reclen;
sp = (uint8_t *)t->bt_cmap;
ep = (uint8_t *)t->bt_emap;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
if (sp >= ep) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
len = t->bt_reclen;
for (p = t->bt_rdata.data;
sp < ep && len > 0; *p++ = *sp++, --len);
if (len != 0)
memset(p, t->bt_bval, len);
if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
}
t->bt_cmap = (caddr_t)sp;
return (RET_SUCCESS);
}
/*
* __REC_VMAP -- Get variable length records from a file.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_vmap(BTREE *t, recno_t top)
{
DBT data;
uint8_t *sp, *ep;
recno_t nrec;
int bval;
sp = (uint8_t *)t->bt_cmap;
ep = (uint8_t *)t->bt_emap;
bval = t->bt_bval;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
if (sp >= ep) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
for (data.data = sp; sp < ep && *sp != bval; ++sp);
data.size = sp - (uint8_t *)data.data;
if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
++sp;
}
t->bt_cmap = (caddr_t)sp;
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,244 @@
/* $NetBSD: rec_open.c,v 1.2 2009/07/16 18:23:32 abs Exp $ */
/* NetBSD: rec_open.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_open.c,v 1.2 2009/07/16 18:23:32 abs Exp $");
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <nbcompat/db.h>
#include "recno.h"
DB *
__rec_open(const char *fname, int flags, mode_t mode, const RECNOINFO *openinfo,
int dflags)
{
BTREE *t;
BTREEINFO btopeninfo;
DB *dbp;
PAGE *h;
struct stat sb;
int rfd = -1; /* pacify gcc */
int sverrno;
dbp = NULL;
/* Open the user's file -- if this fails, we're done. */
if (fname != NULL) {
if ((rfd = open(fname, flags, mode)) == -1)
return (NULL);
if (fcntl(rfd, F_SETFD, FD_CLOEXEC) == -1)
goto err;
}
/* Create a btree in memory (backed by disk). */
if (openinfo) {
if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
goto einval;
btopeninfo.flags = 0;
btopeninfo.cachesize = openinfo->cachesize;
btopeninfo.maxkeypage = 0;
btopeninfo.minkeypage = 0;
btopeninfo.psize = openinfo->psize;
btopeninfo.compare = NULL;
btopeninfo.prefix = NULL;
btopeninfo.lorder = openinfo->lorder;
dbp = __bt_open(openinfo->bfname,
O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
} else
dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
if (dbp == NULL)
goto err;
/*
* Some fields in the tree structure are recno specific. Fill them
* in and make the btree structure look like a recno structure. We
* don't change the bt_ovflsize value, it's close enough and slightly
* bigger.
*/
t = dbp->internal;
if (openinfo) {
if (openinfo->flags & R_FIXEDLEN) {
F_SET(t, R_FIXLEN);
t->bt_reclen = openinfo->reclen;
if (t->bt_reclen == 0)
goto einval;
}
t->bt_bval = openinfo->bval;
} else
t->bt_bval = '\n';
F_SET(t, R_RECNO);
if (fname == NULL)
F_SET(t, R_EOF | R_INMEM);
else
t->bt_rfd = rfd;
if (fname != NULL) {
/*
* In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
* Unfortunately, that's not portable, so we use lseek
* and check the errno values.
*/
errno = 0;
if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, R_RDONLY);
break;
default:
goto einval;
}
slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
goto err;
F_SET(t, R_CLOSEFP);
t->bt_irec =
F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
} else {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, R_RDONLY);
break;
case O_RDWR:
break;
default:
goto einval;
}
if (fstat(rfd, &sb))
goto err;
/*
* Kluge -- we'd like to test to see if the file is too
* big to mmap. Since, we don't know what size or type
* off_t's or size_t's are, what the largest unsigned
* integral type is, or what random insanity the local
* C compiler will perpetrate, doing the comparison in
* a portable way is flatly impossible. Hope that mmap
* fails if the file is too large.
*/
if (sb.st_size == 0)
F_SET(t, R_EOF);
else {
#if !defined(MMAP_NOT_AVAILABLE) && 0
/*
* XXX
* Mmap doesn't work correctly on many current
* systems. In particular, it can fail subtly,
* with cache coherency problems. Don't use it
* for now.
*/
t->bt_msize = sb.st_size;
if ((t->bt_smap = mmap(NULL, t->bt_msize,
PROT_READ, MAP_FILE | MAP_PRIVATE, rfd,
(off_t)0)) == (caddr_t)-1)
goto slow;
t->bt_cmap = t->bt_smap;
t->bt_emap = t->bt_smap + sb.st_size;
t->bt_irec = F_ISSET(t, R_FIXLEN) ?
__rec_fmap : __rec_vmap;
F_SET(t, R_MEMMAPPED);
#else
goto slow;
#endif
}
}
}
/* Use the recno routines. */
dbp->close = __rec_close;
dbp->del = __rec_delete;
dbp->fd = __rec_fd;
dbp->get = __rec_get;
dbp->put = __rec_put;
dbp->seq = __rec_seq;
dbp->sync = __rec_sync;
/* If the root page was created, reset the flags. */
if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
goto err;
if ((h->flags & P_TYPE) == P_BLEAF) {
F_CLR(h, P_TYPE);
F_SET(h, P_RLEAF);
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
} else
mpool_put(t->bt_mp, h, 0);
if (openinfo && openinfo->flags & R_SNAPSHOT &&
!F_ISSET(t, R_EOF | R_INMEM) &&
t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
goto err;
return (dbp);
einval: errno = EINVAL;
err: sverrno = errno;
if (dbp != NULL)
(void)__bt_close(dbp);
if (fname != NULL)
(void)close(rfd);
errno = sverrno;
return (NULL);
}
int
__rec_fd(const DB *dbp)
{
BTREE *t;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* In-memory database can't have a file descriptor. */
if (F_ISSET(t, R_INMEM)) {
errno = ENOENT;
return (-1);
}
return (t->bt_rfd);
}

View File

@@ -0,0 +1,276 @@
/* $NetBSD: rec_put.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_put.c,v 1.17 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_put.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __REC_PUT -- Add a recno item to the tree.
*
* Parameters:
* dbp: pointer to access method
* key: key
* data: data
* flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
* already in the tree and R_NOOVERWRITE specified.
*/
int
__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
{
BTREE *t;
DBT fdata, tdata;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/*
* If using fixed-length records, and the record is long, return
* EINVAL. If it's short, pad it out. Use the record data return
* memory, it's only short-term.
*/
if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
if (data->size > t->bt_reclen)
goto einval;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data = t->bt_rdata.data == NULL ?
malloc(t->bt_reclen) :
realloc(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
memmove(t->bt_rdata.data, data->data, data->size);
memset((char *)t->bt_rdata.data + data->size,
t->bt_bval, t->bt_reclen - data->size);
fdata.data = t->bt_rdata.data;
fdata.size = t->bt_reclen;
} else {
fdata.data = data->data;
fdata.size = data->size;
}
switch (flags) {
case R_CURSOR:
if (!F_ISSET(&t->bt_cursor, CURS_INIT))
goto einval;
nrec = t->bt_cursor.rcursor;
break;
case R_SETCURSOR:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
break;
case R_IAFTER:
if ((nrec = *(recno_t *)key->data) == 0) {
nrec = 1;
flags = R_IBEFORE;
}
break;
case 0:
case R_IBEFORE:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
break;
case R_NOOVERWRITE:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
if (nrec <= t->bt_nrecs)
return (RET_SPECIAL);
break;
default:
einval: errno = EINVAL;
return (RET_ERROR);
}
/*
* Make sure that records up to and including the put record are
* already in the database. If skipping records, create empty ones.
*/
if (nrec > t->bt_nrecs) {
if (!F_ISSET(t, R_EOF | R_INMEM) &&
t->bt_irec(t, nrec) == RET_ERROR)
return (RET_ERROR);
if (nrec > t->bt_nrecs + 1) {
if (F_ISSET(t, R_FIXLEN)) {
if ((tdata.data =
(void *)malloc(t->bt_reclen)) == NULL)
return (RET_ERROR);
tdata.size = t->bt_reclen;
memset(tdata.data, t->bt_bval, tdata.size);
} else {
tdata.data = NULL;
tdata.size = 0;
}
while (nrec > t->bt_nrecs + 1)
if (__rec_iput(t,
t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
return (RET_ERROR);
if (F_ISSET(t, R_FIXLEN))
free(tdata.data);
}
}
if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
return (status);
if (flags == R_SETCURSOR)
t->bt_cursor.rcursor = nrec;
F_SET(t, R_MODIFIED);
return (__rec_ret(t, NULL, nrec, key, NULL));
}
/*
* __REC_IPUT -- Add a recno item to the tree.
*
* Parameters:
* t: tree
* nrec: record number
* data: data
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
{
DBT tdata;
EPG *e;
PAGE *h;
indx_t idx, nxtindex;
pgno_t pg;
uint32_t nbytes;
int dflags, status;
char *dest, db[NOVFLSIZE];
/*
* If the data won't fit on a page, store it on indirect pages.
*
* XXX
* If the insert fails later on, these pages aren't recovered.
*/
if (data->size > t->bt_ovflsize) {
if (__ovfl_put(t, data, &pg) == RET_ERROR)
return (RET_ERROR);
tdata.data = db;
tdata.size = NOVFLSIZE;
*(pgno_t *)(void *)db = pg;
_DBFIT(data->size, uint32_t);
*(uint32_t *)(void *)(db + sizeof(pgno_t)) =
(uint32_t)data->size;
dflags = P_BIGDATA;
data = &tdata;
} else
dflags = 0;
/* __rec_search pins the returned page. */
if ((e = __rec_search(t, nrec,
nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
SINSERT : SEARCH)) == NULL)
return (RET_ERROR);
h = e->page;
idx = e->index;
/*
* Add the specified key/data pair to the tree. The R_IAFTER and
* R_IBEFORE flags insert the key after/before the specified key.
*
* Pages are split as required.
*/
switch (flags) {
case R_IAFTER:
++idx;
break;
case R_IBEFORE:
break;
default:
if (nrec < t->bt_nrecs &&
__rec_dleaf(t, h, (uint32_t)idx) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
break;
}
/*
* If not enough room, split the page. The split code will insert
* the key and data and unpin the current page. If inserting into
* the offset array, shift the pointers up.
*/
nbytes = NRLEAFDBT(data->size);
if ((uint32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
status = __bt_split(t, h, NULL, data, dflags, nbytes,
(uint32_t)idx);
if (status == RET_SUCCESS)
++t->bt_nrecs;
return (status);
}
if (idx < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + idx + 1, h->linp + idx,
(nxtindex - idx) * sizeof(indx_t));
h->lower += sizeof(indx_t);
h->linp[idx] = h->upper -= nbytes;
dest = (char *)(void *)h + h->upper;
WR_RLEAF(dest, data, dflags);
++t->bt_nrecs;
F_SET(t, B_MODIFIED);
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,124 @@
/* $NetBSD: rec_search.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_search.c,v 1.14 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_search.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __REC_SEARCH -- Search a btree for a key.
*
* Parameters:
* t: tree to search
* recno: key to find
* op: search operation
*
* Returns:
* EPG for matching record, if any, or the EPG for the location of the
* key, if it were inserted into the tree.
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__rec_search(BTREE *t, recno_t recno, enum SRCHOP op)
{
indx_t idx;
PAGE *h;
EPGNO *parent;
RINTERNAL *r;
pgno_t pg;
indx_t top;
recno_t total;
int sverrno;
BT_CLR(t);
for (pg = P_ROOT, total = 0;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
goto err;
if (h->flags & P_RLEAF) {
t->bt_cur.page = h;
t->bt_cur.index = recno - total;
return (&t->bt_cur);
}
for (idx = 0, top = NEXTINDEX(h);;) {
r = GETRINTERNAL(h, idx);
if (++idx == top || total + r->nrecs > recno)
break;
total += r->nrecs;
}
BT_PUSH(t, pg, idx - 1);
pg = r->pgno;
switch (op) {
case SDELETE:
--GETRINTERNAL(h, (idx - 1))->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
case SINSERT:
++GETRINTERNAL(h, (idx - 1))->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
case SEARCH:
mpool_put(t->bt_mp, h, 0);
break;
}
}
/* Try and recover the tree. */
err: sverrno = errno;
if (op != SEARCH)
while ((parent = BT_POP(t)) != NULL) {
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
break;
if (op == SINSERT)
--GETRINTERNAL(h, parent->index)->nrecs;
else
++GETRINTERNAL(h, parent->index)->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
}
errno = sverrno;
return (NULL);
}

View File

@@ -0,0 +1,129 @@
/* $NetBSD: rec_seq.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_seq.c,v 1.14 2008/09/11 12:58:00 joerg Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_seq.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __REC_SEQ -- Recno sequential scan interface.
*
* Parameters:
* dbp: pointer to access method
* key: key for positioning and return value
* data: data return value
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
int
__rec_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG *e;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
switch(flags) {
case R_CURSOR:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
break;
case R_NEXT:
if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
nrec = t->bt_cursor.rcursor + 1;
break;
}
/* FALLTHROUGH */
case R_FIRST:
nrec = 1;
break;
case R_PREV:
if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
if ((nrec = t->bt_cursor.rcursor - 1) == 0)
return (RET_SPECIAL);
break;
}
/* FALLTHROUGH */
case R_LAST:
if (!F_ISSET(t, R_EOF | R_INMEM) &&
t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
return (RET_ERROR);
nrec = t->bt_nrecs;
break;
default:
einval: errno = EINVAL;
return (RET_ERROR);
}
if (t->bt_nrecs == 0 || nrec > t->bt_nrecs) {
if (!F_ISSET(t, R_EOF | R_INMEM) &&
(status = t->bt_irec(t, nrec)) != RET_SUCCESS)
return (status);
if (t->bt_nrecs == 0 || nrec > t->bt_nrecs)
return (RET_SPECIAL);
}
if ((e = __rec_search(t, nrec - 1, SEARCH)) == NULL)
return (RET_ERROR);
F_SET(&t->bt_cursor, CURS_INIT);
t->bt_cursor.rcursor = nrec;
status = __rec_ret(t, e, nrec, key, data);
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e->page, 0);
else
t->bt_pinned = e->page;
return (status);
}

View File

@@ -0,0 +1,119 @@
/* $NetBSD: rec_utils.c,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: rec_utils.c,v 1.12 2008/09/10 17:52:36 joerg Exp */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: rec_utils.c,v 1.1 2008/10/10 00:21:44 joerg Exp $");
#include <sys/param.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nbcompat/db.h>
#include "recno.h"
/*
* __rec_ret --
* Build return data.
*
* Parameters:
* t: tree
* e: key/data pair to be returned
* nrec: record number
* key: user's key structure
* data: user's data structure
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_ret(BTREE *t, EPG *e, recno_t nrec, DBT *key, DBT *data)
{
RLEAF *rl;
void *p;
if (key == NULL)
goto dataonly;
/* We have to copy the key, it's not on the page. */
if (sizeof(recno_t) > t->bt_rkey.size) {
p = (void *)(t->bt_rkey.data == NULL ?
malloc(sizeof(recno_t)) :
realloc(t->bt_rkey.data, sizeof(recno_t)));
if (p == NULL)
return (RET_ERROR);
t->bt_rkey.data = p;
t->bt_rkey.size = sizeof(recno_t);
}
memmove(t->bt_rkey.data, &nrec, sizeof(recno_t));
key->size = sizeof(recno_t);
key->data = t->bt_rkey.data;
dataonly:
if (data == NULL)
return (RET_SUCCESS);
/*
* We must copy big keys/data to make them contigous. Otherwise,
* leave the page pinned and don't copy unless the user specified
* concurrent access.
*/
rl = GETRLEAF(e->page, e->index);
if (rl->flags & P_BIGDATA) {
if (__ovfl_get(t, rl->bytes,
&data->size, &t->bt_rdata.data, &t->bt_rdata.size))
return (RET_ERROR);
data->data = t->bt_rdata.data;
} else if (F_ISSET(t, B_DB_LOCK)) {
/* Use +1 in case the first record retrieved is 0 length. */
if (rl->dsize + 1 > t->bt_rdata.size) {
p = (void *)(t->bt_rdata.data == NULL ?
malloc(rl->dsize + 1) :
realloc(t->bt_rdata.data, rl->dsize + 1));
if (p == NULL)
return (RET_ERROR);
t->bt_rdata.data = p;
t->bt_rdata.size = rl->dsize + 1;
}
memmove(t->bt_rdata.data, rl->bytes, rl->dsize);
data->size = rl->dsize;
data->data = t->bt_rdata.data;
} else {
data->size = rl->dsize;
data->data = rl->bytes;
}
return (RET_SUCCESS);
}

View File

@@ -0,0 +1,38 @@
/* $NetBSD: recno.h,v 1.1 2008/10/10 00:21:44 joerg Exp $ */
/* NetBSD: recno.h,v 1.6 2003/08/07 16:42:44 agc Exp */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)recno.h 8.1 (Berkeley) 6/4/93
*/
enum SRCHOP { SDELETE, SINSERT, SEARCH}; /* Rec_search operation. */
#include "../btree/btree.h"
#include "extern.h"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
/* $NetBSD: err.c,v 1.4 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright 1997-2000 Luke Mewburn <lukem@netbsd.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: err.c,v 1.4 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#ifndef __NO_NAMESPACE_H /* XXX */
#if 0
#include "namespace.h"
#endif
#endif
#include <nbcompat/err.h>
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if 0
#ifdef __weak_alias
__weak_alias(err, _err)
#endif
#endif
void
err(int eval, const char *fmt, ...)
{
va_list ap;
int sverrno;
sverrno = errno;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
va_end(ap);
(void)fprintf(stderr, "%s\n", strerror(sverrno));
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(eval);
}
void
verr(eval, fmt, ap)
int eval;
const char *fmt;
va_list ap;
{
int sverrno;
sverrno = errno;
(void)fprintf(stderr, "%s: ", getprogname());
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
(void)fprintf(stderr, "%s\n", strerror(sverrno));
exit(eval);
}
void
verrx(eval, fmt, ap)
int eval;
const char *fmt;
va_list ap;
{
(void)fprintf(stderr, "%s: ", getprogname());
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, "\n");
exit(eval);
}

View File

@@ -0,0 +1,81 @@
/* $NetBSD: fgetln.c,v 1.5 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
/*
* XXX: This implementation doesn't quite conform to the specification
* in the man page, in that it only manages one buffer at all, not one
* per stdio stream. Since the previous implementation did the same,
* this won't break anything new.
*/
char *
fgetln(fp, len)
FILE *fp;
size_t *len;
{
static char *buf = NULL;
static size_t bufsiz = 0;
static size_t buflen = 0;
int c;
if (buf == NULL) {
bufsiz = BUFSIZ;
if ((buf = malloc(bufsiz)) == NULL)
return NULL;
}
buflen = 0;
while ((c = fgetc(fp)) != EOF) {
if (buflen >= bufsiz) {
size_t nbufsiz = bufsiz + BUFSIZ;
char *nbuf = realloc(buf, nbufsiz);
if (nbuf == NULL) {
int oerrno = errno;
free(buf);
errno = oerrno;
buf = NULL;
return NULL;
}
buf = nbuf;
bufsiz = nbufsiz;
}
buf[buflen++] = c;
if (c == '\n')
break;
}
*len = buflen;
return buflen == 0 ? NULL : buf;
}

View File

@@ -0,0 +1,88 @@
/* $NetBSD: findenv.c,v 1.1 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: findenv.c,v 1.1 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdlib.h>
#include <nbcompat/string.h>
#if 0
#include "local.h"
#include "reentrant.h"
#endif
#if 0
#ifdef _REENTRANT
rwlock_t __environ_lock = RWLOCK_INITIALIZER;
#endif
#endif
extern char **environ;
/*
* __findenv --
* Returns pointer to value associated with name, if any, else NULL.
* Sets offset to be the offset of the name/value combination in the
* environmental array, for use by setenv(3) and unsetenv(3).
* Explicitly removes '=' in argument name.
*
* This routine *should* be a static; don't use it.
*/
char *
__findenv(name, offset)
const char *name;
int *offset;
{
size_t len;
const char *np;
char **p, *c;
if (name == NULL || environ == NULL)
return (NULL);
for (np = name; *np && *np != '='; ++np)
continue;
len = np - name;
for (p = environ; (c = *p) != NULL; ++p)
if (strncmp(c, name, len) == 0 && c[len] == '=') {
*offset = p - environ;
return (c + len + 1);
}
return (NULL);
}

View File

@@ -0,0 +1,203 @@
/* $NetBSD: fnmatch.c,v 1.3 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
#else
__RCSID("$NetBSD: fnmatch.c,v 1.3 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
/*
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
* Compares a filename or pathname to a pattern.
*/
#if 0
#include "namespace.h"
#endif
#include <nbcompat/assert.h>
#include <nbcompat/ctype.h>
#include <nbcompat/fnmatch.h>
#include <nbcompat/string.h>
#define EOS '\0'
static const char *rangematch(const char *, int, int);
static int
foldcase(int ch, int flags)
{
if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
return (tolower(ch));
return (ch);
}
#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
int
fnmatch(pattern, string, flags)
const char *pattern, *string;
int flags;
{
const char *stringstart;
char c, test;
_DIAGASSERT(pattern != NULL);
_DIAGASSERT(string != NULL);
for (stringstart = string;;)
switch (c = FOLDCASE(*pattern++, flags)) {
case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/')
return (0);
return (*string == EOS ? 0 : FNM_NOMATCH);
case '?':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
++string;
break;
case '*':
c = FOLDCASE(*pattern, flags);
/* Collapse multiple stars. */
while (c == '*')
c = FOLDCASE(*++pattern, flags);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
/* Optimize for pattern with * at end or before /. */
if (c == EOS) {
if (flags & FNM_PATHNAME)
return ((flags & FNM_LEADING_DIR) ||
strchr(string, '/') == NULL ?
0 : FNM_NOMATCH);
else
return (0);
} else if (c == '/' && flags & FNM_PATHNAME) {
if ((string = strchr(string, '/')) == NULL)
return (FNM_NOMATCH);
break;
}
/* General case, use recursion. */
while ((test = FOLDCASE(*string, flags)) != EOS) {
if (!fnmatch(pattern, string,
flags & ~FNM_PERIOD))
return (0);
if (test == '/' && flags & FNM_PATHNAME)
break;
++string;
}
return (FNM_NOMATCH);
case '[':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && flags & FNM_PATHNAME)
return (FNM_NOMATCH);
if ((pattern =
rangematch(pattern, FOLDCASE(*string, flags),
flags)) == NULL)
return (FNM_NOMATCH);
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
c = '\\';
--pattern;
}
}
/* FALLTHROUGH */
default:
if (c != FOLDCASE(*string++, flags))
return (FNM_NOMATCH);
break;
}
/* NOTREACHED */
}
static const char *
rangematch(pattern, test, flags)
const char *pattern;
int test, flags;
{
int negate, ok;
char c, c2;
_DIAGASSERT(pattern != NULL);
/*
* A bracket expression starting with an unquoted circumflex
* character produces unspecified results (IEEE 1003.2-1992,
* 3.13.2). This implementation treats it like '!', for
* consistency with the regular expression syntax.
* J.T. Conklin (conklin@ngai.kaleida.com)
*/
if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
++pattern;
for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = FOLDCASE(*pattern++, flags);
if (c == EOS)
return (NULL);
if (*pattern == '-'
&& (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
c2 != ']') {
pattern += 2;
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
c2 = FOLDCASE(*pattern++, flags);
if (c2 == EOS)
return (NULL);
if (c <= test && test <= c2)
ok = 1;
} else if (c == test)
ok = 1;
}
return (ok == negate ? NULL : pattern);
}

View File

@@ -0,0 +1,249 @@
/* $NetBSD: fparseln.c,v 1.3 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: fparseln.c,v 1.3 2004/08/23 03:32:12 jlam Exp $");
#endif /* LIBC_SCCS and not lint */
#if 0
#include "namespace.h"
#endif
#include <nbcompat/assert.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdio.h>
#include <nbcompat/string.h>
#include <nbcompat/stdlib.h>
#if 0
#ifdef __weak_alias
__weak_alias(fparseln,_fparseln)
#endif
#endif
#if ! HAVE_FPARSELN
#if 0
#ifndef HAVE_NBTOOL_CONFIG_H
#include "reentrant.h"
#include "local.h"
#else
#define FLOCKFILE(fp)
#define FUNLOCKFILE(fp)
#endif
#endif
#if 0
#if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H
#define __fgetln(f, l) __fgetstr(f, l, '\n')
#else
#define __fgetln(f, l) fgetln(f, l)
#endif
#endif
static int isescaped(const char *, const char *, int);
/* isescaped():
* Return true if the character in *p that belongs to a string
* that starts in *sp, is escaped by the escape character esc.
*/
static int
isescaped(const char *sp, const char *p, int esc)
{
const char *cp;
size_t ne;
/* No escape character */
if (esc == '\0')
return 1;
/* Count the number of escape characters that precede ours */
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
continue;
/* Return true if odd number of escape characters */
return (ne & 1) != 0;
}
/* fparseln():
* Read a line from a file parsing continuations ending in \
* and eliminating trailing newlines, or comments starting with
* the comment char.
*/
char *
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
{
static const char dstr[3] = { '\\', '\\', '#' };
size_t s, len;
char *buf;
char *ptr, *cp;
int cnt;
char esc, con, nl, com;
len = 0;
buf = NULL;
cnt = 1;
if (str == NULL)
str = dstr;
esc = str[0];
con = str[1];
com = str[2];
/*
* XXX: it would be cool to be able to specify the newline character,
* but unfortunately, fgetln does not let us
*/
nl = '\n';
while (cnt) {
cnt = 0;
if (lineno)
(*lineno)++;
if ((ptr = fgetln(fp, &s)) == NULL)
break;
if (s && com) { /* Check and eliminate comments */
for (cp = ptr; cp < ptr + s; cp++)
if (*cp == com && !isescaped(ptr, cp, esc)) {
s = cp - ptr;
cnt = s == 0 && buf == NULL;
break;
}
}
if (s && nl) { /* Check and eliminate newlines */
cp = &ptr[s - 1];
if (*cp == nl)
s--; /* forget newline */
}
if (s && con) { /* Check and eliminate continuations */
cp = &ptr[s - 1];
if (*cp == con && !isescaped(ptr, cp, esc)) {
s--; /* forget escape */
cnt = 1;
}
}
if (s == 0 && buf != NULL)
continue;
if ((cp = realloc(buf, len + s + 1)) == NULL) {
free(buf);
return NULL;
}
buf = cp;
(void) memcpy(buf + len, ptr, s);
len += s;
buf[len] = '\0';
}
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
strchr(buf, esc) != NULL) {
ptr = cp = buf;
while (cp[0] != '\0') {
int skipesc;
while (cp[0] != '\0' && cp[0] != esc)
*ptr++ = *cp++;
if (cp[0] == '\0' || cp[1] == '\0')
break;
skipesc = 0;
if (cp[1] == com)
skipesc += (flags & FPARSELN_UNESCCOMM);
if (cp[1] == con)
skipesc += (flags & FPARSELN_UNESCCONT);
if (cp[1] == esc)
skipesc += (flags & FPARSELN_UNESCESC);
if (cp[1] != com && cp[1] != con && cp[1] != esc)
skipesc = (flags & FPARSELN_UNESCREST);
if (skipesc)
cp++;
else
*ptr++ = *cp++;
*ptr++ = *cp++;
}
*ptr = '\0';
len = strlen(buf);
}
if (size)
*size = len;
return buf;
}
#ifdef TEST
int main(int, char *[]);
int
main(int argc, char *argv[])
{
char *ptr;
size_t size, line;
line = 0;
while ((ptr = fparseln(stdin, &size, &line, NULL,
FPARSELN_UNESCALL)) != NULL)
printf("line %d (%d) |%s|\n", line, size, ptr);
return 0;
}
/*
# This is a test
line 1
line 2 \
line 3 # Comment
line 4 \# Not comment \\\\
# And a comment \
line 5 \\\
line 6
*/
#endif /* TEST */
#endif /* ! HAVE_FPARSELN */

View File

@@ -0,0 +1,12 @@
/* $NetBSD: fts.c,v 1.1 2004/08/23 03:32:12 jlam Exp $ */
/*
* Written by Jason R. Thorpe <thorpej@NetBSD.org>, October 21, 1997.
* Public domain.
*/
#if 0
#define __LIBC12_SOURCE__
#endif
#include "__fts13.c"

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Pseudo-implementation of RFC2553 name / address resolution functions
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For example, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include <nbcompat.h>
#include <nbcompat/netdb.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef HAVE_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct hostent *hp;
char tmpserv[16];
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
return (EAI_FAMILY);
if (serv != NULL) {
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
if (strlcpy(serv, tmpserv, servlen) >= servlen)
return (EAI_MEMORY);
}
if (host != NULL) {
if (flags & NI_NUMERICHOST) {
if (strlcpy(host, inet_ntoa(sin->sin_addr),
hostlen) >= hostlen)
return (EAI_MEMORY);
else
return (0);
} else {
hp = gethostbyaddr((char *)&sin->sin_addr,
sizeof(struct in_addr), AF_INET);
if (hp == NULL)
return (EAI_NODATA);
if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
return (EAI_MEMORY);
else
return (0);
}
}
return (0);
}
#endif /* !HAVE_GETNAMEINFO */
#ifndef HAVE_GAI_STRERROR
char *
gai_strerror(int err)
{
switch (err) {
case EAI_NODATA:
return ("no address associated with name");
case EAI_MEMORY:
return ("memory allocation failure");
case EAI_NONAME:
return ("nodename nor servname provided, or not known");
case EAI_FAMILY:
return ("ai_family not supported");
case EAI_AGAIN:
return ("temparary failure");
case EAI_FAIL:
return ("unrecoverable failure");
default:
return ("unknown/invalid error");
}
}
#endif /* !HAVE_GAI_STRERROR */
#ifndef HAVE_GETADDRINFO
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
for(; ai != NULL;) {
next = ai->ai_next;
free(ai);
ai = next;
}
}
static struct
addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
{
struct addrinfo *ai;
ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
if (ai == NULL)
return (NULL);
memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
ai->ai_addr = (struct sockaddr *)(ai + 1);
/* XXX -- ssh doesn't use sa_len */
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
/* XXX: the following is not generally correct, but does what we want */
if (hints->ai_socktype)
ai->ai_socktype = hints->ai_socktype;
else
ai->ai_socktype = SOCK_STREAM;
if (hints->ai_protocol)
ai->ai_protocol = hints->ai_protocol;
return (ai);
}
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct hostent *hp;
struct servent *sp;
struct in_addr in;
int i;
long int port;
u_long addr;
port = 0;
if (hints && hints->ai_family != AF_UNSPEC &&
hints->ai_family != AF_INET)
return (EAI_FAMILY);
if (servname != NULL) {
char *cp;
port = strtol(servname, &cp, 10);
if (port > 0 && port <= 65535 && *cp == '\0')
port = htons(port);
else if ((sp = getservbyname(servname, NULL)) != NULL)
port = sp->s_port;
else
port = 0;
}
if (hints && hints->ai_flags & AI_PASSIVE) {
addr = htonl(0x00000000);
if (hostname && inet_aton(hostname, &in) != 0)
addr = in.s_addr;
*res = malloc_ai(port, addr, hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (!hostname) {
*res = malloc_ai(port, htonl(0x7f000001), hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (inet_aton(hostname, &in)) {
*res = malloc_ai(port, in.s_addr, hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
/* Don't try DNS if AI_NUMERICHOST is set */
if (hints && hints->ai_flags & AI_NUMERICHOST)
return (EAI_NONAME);
hp = gethostbyname(hostname);
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
struct addrinfo *cur, *prev;
cur = prev = *res = NULL;
for (i = 0; hp->h_addr_list[i]; i++) {
struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
cur = malloc_ai(port, in->s_addr, hints);
if (cur == NULL) {
if (*res != NULL)
freeaddrinfo(*res);
return (EAI_MEMORY);
}
if (prev)
prev->ai_next = cur;
else
*res = cur;
prev = cur;
}
return (0);
}
return (EAI_NODATA);
}
#endif /* !HAVE_GETADDRINFO */

View File

@@ -0,0 +1,117 @@
/* $NetBSD: getenv.c,v 1.4 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: getenv.c,v 1.4 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <nbcompat/assert.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdlib.h>
#include <nbcompat/string.h>
#if 0
#include "local.h"
#include "reentrant.h"
#endif
char *__findenv __P((const char *, int *));
#if 0
#ifdef _REENTRANT
rwlock_t __environ_lock = RWLOCK_INITIALIZER;
#endif
#endif
extern char **environ;
#ifndef rwlock_rdlock
#define rwlock_rdlock(lock) ((void)0)
#endif
#ifndef rwlock_unlock
#define rwlock_unlock(lock) ((void)0)
#endif
/*
* getenv --
* Returns ptr to value associated with name, if any, else NULL.
*/
char *
getenv(name)
const char *name;
{
int offset;
char *result;
_DIAGASSERT(name != NULL);
rwlock_rdlock(&__environ_lock);
result = __findenv(name, &offset);
rwlock_unlock(&__environ_lock);
return (result);
}
/*
* __findenv --
* Returns pointer to value associated with name, if any, else NULL.
* Sets offset to be the offset of the name/value combination in the
* environmental array, for use by setenv(3) and unsetenv(3).
* Explicitly removes '=' in argument name.
*
* This routine *should* be a static; don't use it.
*/
char *
__findenv(name, offset)
const char *name;
int *offset;
{
size_t len;
const char *np;
char **p, *c;
if (name == NULL || environ == NULL)
return (NULL);
for (np = name; *np && *np != '='; ++np)
continue;
len = np - name;
for (p = environ; (c = *p) != NULL; ++p)
if (strncmp(c, name, len) == 0 && c[len] == '=') {
*offset = p - environ;
return (c + len + 1);
}
return (NULL);
}

View File

@@ -0,0 +1,149 @@
/* $NetBSD: getopt.c,v 1.1 2009/03/22 22:33:13 joerg Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: getopt.c,v 1.1 2009/03/22 22:33:13 joerg Exp $");
#if 0
#include "namespace.h"
#endif
#include <nbcompat/assert.h>
#include <errno.h>
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/string.h>
#include <nbcompat/unistd.h>
#undef __UNCONST
#define __UNCONST(a) ((void *)(size_t)(const void *)(a))
#if 0
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
#endif
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
static const char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(ostr != NULL);
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
place = nargv[optind];
if (optind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
optopt = *place++;
if (optopt == '-' && *place == 0) {
/* "--" => end of options */
++optind;
place = EMSG;
return (-1);
}
if (optopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL)
return -1;
optopt = '-';
}
} else
optopt = *place++;
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*place == 0)
++optind;
if (opterr && *ostr != ':')
(void)fprintf(stderr,
"%s: unknown option -- %c\n", getprogname(),
optopt);
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
optarg = NULL;
if (*place == 0)
++optind;
} else {
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place)
optarg = __UNCONST(place);
else if (nargc > ++optind)
optarg = nargv[optind];
else {
/* option-argument absent */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
getprogname(), optopt);
return (BADCH);
}
place = EMSG;
++optind;
}
return (optopt); /* return option letter */
}

View File

@@ -0,0 +1,490 @@
/* $NetBSD: getopt_long.c,v 1.11 2009/04/14 17:34:41 joerg Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
__RCSID("$NetBSD: getopt_long.c,v 1.11 2009/04/14 17:34:41 joerg Exp $");
#if 0
#include "namespace.h"
#endif
#include <nbcompat/assert.h>
#include <nbcompat/err.h>
#include <errno.h>
#if HAVE_NBTOOL_CONFIG_H
#include "compat_getopt.h"
#else
#include <nbcompat/getopt.h>
#endif
#include <nbcompat/stdlib.h>
#include <nbcompat/string.h>
#undef __UNCONST
#define __UNCONST(a) ((void *)(size_t)(const void *)(a))
#if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
#define REPLACE_GETOPT
#endif
#ifdef REPLACE_GETOPT
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
char *optarg; /* argument associated with option */
#endif
#if !HAVE_DECL_OPTRESET
int optreset; /* reset getopt */
#endif
#if 0
#ifdef __weak_alias
__weak_alias(getopt_long,_getopt_long)
#endif
#endif
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|| (IGNORE_FIRST && options[1] != ':')))
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
/* XXX: GNU ignores PC if *options == '-' */
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
/* return values */
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|| (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char **, const char *);
static int gcd(int, int);
static void permute_args(int, int, int, char **);
static const char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
_DIAGASSERT(nargv != NULL);
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
nargv[pos] = nargv[cstart];
nargv[cstart] = swap;
}
}
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Returns -2 if -- is found (can be long option or end of options marker).
*/
static int
getopt_internal(int nargc, char **nargv, const char *options)
{
char *oli; /* option letter list index */
int optchar;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
optarg = NULL;
/*
* XXX Some programs (like rsyncd) expect to be able to
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
if (optind == 0)
optind = 1;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) { /* found non-option */
place = EMSG;
if (IN_ORDER) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
/*
* if no permutation wanted, stop parsing
* at first non-option
*/
return -1;
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') { /* found "--" */
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if (*place)
return -2;
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return BADARG;
} else /* white space */
place = nargv[optind];
/*
* Handle -W arg the same as --arg (which causes getopt to
* stop parsing).
*/
return -2;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = __UNCONST(place);
/* XXX: disable test for :: if PC? (GNU doesn't) */
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the real getopt]
*/
int
getopt(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
retval = getopt_internal(nargc, __UNCONST(nargv), options);
if (retval == -2) {
++optind;
/*
* We found an option (--), so if we skipped non-options,
* we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind,
nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
retval = -1;
}
return retval;
}
#endif
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
int retval;
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
_DIAGASSERT(long_options != NULL);
/* idx may be NULL */
retval = getopt_internal(nargc, __UNCONST(nargv), options);
if (retval == -2) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
current_argv = __UNCONST(place);
match = -1;
ambiguous = 0;
optind++;
place = EMSG;
if (*current_argv == '\0') { /* found "--" */
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, __UNCONST(nargv));
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return BADCH;
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of
* flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return BADARG;
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use
* next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':'
* indicates no error should be generated
*/
if (PRINT_ERROR)
warnx(recargstring, current_argv);
/*
* XXX: GNU sets optopt to val regardless
* of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else { /* unknown option */
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return BADCH;
}
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
} else
retval = long_options[match].val;
if (idx)
*idx = match;
}
return retval;
#undef IDENTICAL_INTERPRETATION
}

View File

@@ -0,0 +1,180 @@
/* $NetBSD: gettemp.c,v 1.2 2007/07/31 13:17:33 joerg Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: gettemp.c,v 1.2 2007/07/31 13:17:33 joerg Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <nbcompat/types.h>
#include <nbcompat/stat.h>
#include <nbcompat/assert.h>
#include <nbcompat/ctype.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/unistd.h>
#if HAVE_NBTOOL_CONFIG_H
#define GETTEMP gettemp
#else
#if 0
#include "reentrant.h"
#include "local.h"
#define GETTEMP __gettemp
#else
#define GETTEMP gettemp
#endif
#endif
int
GETTEMP(path, doopen, domkdir)
char *path;
int *doopen;
int domkdir;
{
char *start, *trv;
struct stat sbuf;
unsigned int pid;
/* To guarantee multiple calls generate unique names even if
the file is not created. 676 different possibilities with 7
or more X's, 26 with 6 or less. */
static char xtra[2] = "aa";
int xcnt = 0;
_DIAGASSERT(path != NULL);
/* doopen may be NULL */
pid = getpid();
/* Move to end of path and count trailing X's. */
for (trv = path; *trv; ++trv)
if (*trv == 'X')
xcnt++;
else
xcnt = 0;
/* Use at least one from xtra. Use 2 if more than 6 X's. */
if (*(trv - 1) == 'X')
*--trv = xtra[0];
if (xcnt > 6 && *(trv - 1) == 'X')
*--trv = xtra[1];
/* Set remaining X's to pid digits with 0's to the left. */
while (*--trv == 'X') {
*trv = (pid % 10) + '0';
pid /= 10;
}
/* update xtra for next call. */
if (xtra[0] != 'z')
xtra[0]++;
else {
xtra[0] = 'a';
if (xtra[1] != 'z')
xtra[1]++;
else
xtra[1] = 'a';
}
/*
* check the target directory; if you have six X's and it
* doesn't exist this runs for a *very* long time.
*/
for (start = trv + 1;; --trv) {
if (trv <= path)
break;
if (*trv == '/') {
*trv = '\0';
if (stat(path, &sbuf))
return (0);
if (!S_ISDIR(sbuf.st_mode)) {
errno = ENOTDIR;
return (0);
}
*trv = '/';
break;
}
}
for (;;) {
if (doopen) {
if ((*doopen =
open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0)
return (1);
if (errno != EEXIST)
return (0);
} else if (domkdir) {
if (mkdir(path, 0700) >= 0)
return (1);
if (errno != EEXIST)
return (0);
} else if (lstat(path, &sbuf))
return (errno == ENOENT ? 1 : 0);
/* tricky little algorithm for backward compatibility */
for (trv = start;;) {
if (!*trv)
return (0);
if (*trv == 'z')
*trv++ = 'a';
else {
if (isdigit((unsigned char)*trv))
*trv = 'a';
else
++*trv;
break;
}
}
}
/*NOTREACHED*/
}
#endif /* !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP */

View File

@@ -0,0 +1,12 @@
/* $NetBSD: glob.c,v 1.4 2004/08/23 03:32:12 jlam Exp $ */
/*
* Written by Jason R. Thorpe <thorpej@NetBSD.org>, October 21, 1997.
* Public domain.
*/
#if 0
#define __LIBC12_SOURCE__
#endif
#include "__glob13.c"

View File

@@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@@ -0,0 +1,57 @@
/* $NetBSD: isblank.c,v 1.5 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)isctype.c 5.2 (Berkeley) 6/1/90";
#else
__RCSID("$NetBSD: isblank.c,v 1.5 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#if 0
#define _ANSI_LIBRARY
#endif
#include <nbcompat/ctype.h>
int
isblank(c)
int c;
{
return(c == ' ' || c == '\t');
}

View File

@@ -0,0 +1,50 @@
/* $NetBSD: lchflags.c,v 1.4 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Emulate lchflags(2), checking path with lstat(2) first to ensure that
* it's not a symlink, and then call chflags(2) */
#include <nbcompat.h>
#include <nbcompat/stat.h>
#include <nbcompat/unistd.h>
int
lchflags(const char *path, unsigned long flags)
{
struct stat psb;
if (lstat(path, &psb) == -1)
return -1;
if (S_ISLNK(psb.st_mode)) {
return 0;
}
return (chflags(path, flags));
}

View File

@@ -0,0 +1,50 @@
/* $NetBSD: lchmod.c,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Emulate lchmod(2), checking path with lstat(2) first to ensure that
* it's not a symlink, and then call chmod(2) */
#include <nbcompat.h>
#include <nbcompat/stat.h>
#include <nbcompat/unistd.h>
int
lchmod(const char *path, mode_t mode)
{
struct stat psb;
if (lstat(path, &psb) == -1)
return -1;
if (S_ISLNK(psb.st_mode)) {
return 0;
}
return (chmod(path, mode));
}

View File

@@ -0,0 +1,50 @@
/* $NetBSD: lchown.c,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Emulate lchown(2), checking path with lstat(2) first to ensure that
* it's not a symlink, and then call chown(2) */
#include <nbcompat.h>
#include <nbcompat/stat.h>
#include <nbcompat/unistd.h>
int
lchown(const char *path, uid_t owner, gid_t group)
{
struct stat psb;
if (lstat(path, &psb) == -1)
return -1;
if (S_ISLNK(psb.st_mode)) {
return 0;
}
return (chown(path, owner, group));
}

View File

@@ -0,0 +1,50 @@
/* $NetBSD: lutimes.c,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Grant Beattie.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Emulate lutimes(2), checking path with lstat(2) first to ensure that
* it's not a symlink, and then call chmod(2) */
#include <nbcompat.h>
#include <nbcompat/stat.h>
#include <nbcompat/unistd.h>
int
lutimes(const char *path, const struct timeval *times)
{
struct stat psb;
if (lstat(path, &psb) == -1)
return -1;
if (S_ISLNK(psb.st_mode)) {
return 0;
}
return (utimes(path, times));
}

View File

@@ -0,0 +1,15 @@
/* $NetBSD: malloc.c,v 1.1.1.1 2003/03/31 05:02:54 grant Exp $ */
#if ! HAVE_MALLOC
#undef malloc
#include <sys/types.h>
void *malloc();
void *rpl_malloc (size_t n)
{
if (n == 0) n = 1;
return malloc(n);
}
#endif

View File

@@ -0,0 +1,377 @@
/* $NetBSD: md5c.c,v 1.7 2008/10/06 12:36:20 joerg Exp $ */
/*
* This file is derived from the RSA Data Security, Inc. MD5 Message-Digest
* Algorithm and has been modified by Jason R. Thorpe <thorpej@NetBSD.org>
* for portability and formatting.
*/
/*
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD5 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
#if defined(_KERNEL) || defined(_STANDALONE)
#include <lib/libkern/libkern.h>
#include <sys/param.h>
#include <sys/md5.h>
#define _DIAGASSERT(x) (void)0
#else
#if 0
#include "namespace.h"
#endif
#include <nbcompat.h>
#include <nbcompat/types.h>
#include <nbcompat/assert.h>
#include <nbcompat/string.h>
#include <nbcompat/md5.h>
#endif /* _KERNEL || _STANDALONE */
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_MD5_H
#if defined(HAVE_MEMSET)
#define ZEROIZE(d, l) memset((d), 0, (l))
#else
# if defined(HAVE_BZERO)
#define ZEROIZE(d, l) bzero((d), (l))
# else
#error You need either memset or bzero
# endif
#endif
typedef unsigned char *POINTER;
typedef uint16_t UINT2;
typedef uint32_t UINT4;
/*
* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
#if 0
#if !defined(_KERNEL) && !defined(_STANDALONE) && defined(__weak_alias)
__weak_alias(MD5Init,_MD5Init)
__weak_alias(MD5Update,_MD5Update)
__weak_alias(MD5Final,_MD5Final)
#endif
#endif
static void MD5Transform __P((UINT4 [4], const unsigned char [64]));
static void Encode __P((unsigned char *, UINT4 *, unsigned int));
static void Decode __P((UINT4 *, const unsigned char *, unsigned int));
/*
* Encodes input (UINT4) into output (unsigned char). Assumes len is
* a multiple of 4.
*/
static void
Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/*
* Decodes input (unsigned char) into output (UINT4). Assumes len is
* a multiple of 4.
*/
static void
Decode (output, input, len)
UINT4 *output;
const unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
static const unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/*
* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/*
* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
* Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/*
* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void
MD5Init(context)
MD5_CTX *context; /* context */
{
_DIAGASSERT(context != 0);
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants. */
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/*
* MD5 block update operation. Continues an MD5 message-digest
* operation, processing another message block, and updating the
* context.
*/
void
MD5Update(context, input, inputLen)
MD5_CTX *context; /* context */
const unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, idx, partLen;
_DIAGASSERT(context != 0);
_DIAGASSERT(input != 0);
/* Compute number of bytes mod 64 */
idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - idx;
/* Transform as many times as possible. */
if (inputLen >= partLen) {
/* LINTED const castaway ok */
memcpy((POINTER)&context->buffer[idx],
(POINTER)input, partLen);
MD5Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform(context->state, &input[i]);
idx = 0;
} else
i = 0;
/* Buffer remaining input */
/* LINTED const castaway ok */
memcpy((POINTER)&context->buffer[idx], (POINTER)&input[i],
inputLen - i);
}
/*
* MD5 finalization. Ends an MD5 message-digest operation, writing the
* message digest and zeroing the context.
*/
void
MD5Final(digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int idx, padLen;
_DIAGASSERT(digest != 0);
_DIAGASSERT(context != 0);
/* Save number of bits */
Encode(bits, context->count, 8);
/* Pad out to 56 mod 64. */
idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (idx < 56) ? (56 - idx) : (120 - idx);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update(context, bits, 8);
/* Store state in digest */
Encode(digest, context->state, 16);
/* Zeroize sensitive information. */
ZEROIZE((POINTER)(void *)context, sizeof(*context));
}
/*
* MD5 basic transformation. Transforms state based on block.
*/
static void
MD5Transform(state, block)
UINT4 state[4];
const unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode(x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information. */
ZEROIZE((POINTER)(void *)x, sizeof (x));
}
#endif /* HAVE_MD5_H */

View File

@@ -0,0 +1,22 @@
/* $NetBSD: md5hl.c,v 1.7 2004/08/23 03:32:12 jlam Exp $ */
/*
* Written by Jason R. Thorpe <thorpej@NetBSD.org>, April 29, 1997.
* Public domain.
*/
#define MDALGORITHM MD5
#if 0
#include "namespace.h"
#endif
#include <nbcompat.h>
#include <nbcompat/md5.h>
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_MD5_H
#include "mdXhl.c"
#endif

View File

@@ -0,0 +1,105 @@
/* $NetBSD: mdXhl.c,v 1.2 2008/10/06 12:36:20 joerg Exp $ */
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* from FreeBSD Id: mdXhl.c,v 1.8 1996/10/25 06:48:12 bde Exp
*/
/*
* Modifed April 29, 1997 by Jason R. Thorpe <thorpej@NetBSD.org>
*/
#include <nbcompat.h>
#include <nbcompat/types.h>
#include <nbcompat/assert.h>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/unistd.h>
#define CONCAT(x,y) __CONCAT(x,y)
#define MDNAME(x) CONCAT(MDALGORITHM,x)
char *
MDNAME(End)(ctx, buf)
MDNAME(_CTX) *ctx;
char *buf;
{
int i;
unsigned char digest[16];
static const char hex[]="0123456789abcdef";
_DIAGASSERT(ctx != 0);
if (buf == NULL)
buf = malloc(33);
if (buf == NULL)
return (NULL);
MDNAME(Final)(digest, ctx);
for (i = 0; i < 16; i++) {
buf[i+i] = hex[(uint32_t)digest[i] >> 4];
buf[i+i+1] = hex[digest[i] & 0x0f];
}
buf[i+i] = '\0';
return (buf);
}
char *
MDNAME(File)(filename, buf)
const char *filename;
char *buf;
{
unsigned char buffer[BUFSIZ];
MDNAME(_CTX) ctx;
int f, i, j;
_DIAGASSERT(filename != 0);
/* buf may be NULL */
MDNAME(Init)(&ctx);
f = open(filename, O_RDONLY, 0666);
if (f < 0)
return NULL;
while ((i = read(f, buffer, sizeof(buffer))) > 0)
MDNAME(Update)(&ctx, buffer, (unsigned int)i);
j = errno;
close(f);
errno = j;
if (i < 0)
return NULL;
return (MDNAME(End)(&ctx, buf));
}
char *
MDNAME(Data)(data, len, buf)
const unsigned char *data;
unsigned int len;
char *buf;
{
MDNAME(_CTX) ctx;
_DIAGASSERT(data != 0);
MDNAME(Init)(&ctx);
MDNAME(Update)(&ctx, data, len);
return (MDNAME(End)(&ctx, buf));
}

View File

@@ -0,0 +1,77 @@
/* $NetBSD: mkdtemp.c,v 1.3 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_NBTOOL_CONFIG_H || !HAVE_MKDTEMP
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: mkdtemp.c,v 1.3 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#if HAVE_NBTOOL_CONFIG_H
#define GETTEMP gettemp
#else
#include <nbcompat/assert.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/unistd.h>
#if 0
#include "reentrant.h"
#include "local.h"
#define GETTEMP __gettemp
#else
#define GETTEMP gettemp
extern int gettemp __P((char *, int *, int));
#endif
#endif
char *
mkdtemp(path)
char *path;
{
_DIAGASSERT(path != NULL);
return (GETTEMP(path, (int *)NULL, 1) ? path : (char *)NULL);
}
#endif /* !HAVE_NBTOOL_CONFIG_H || !HAVE_MKDTEMP */

View File

@@ -0,0 +1,79 @@
/* $NetBSD: mkstemp.c,v 1.4 2004/08/23 03:32:12 jlam Exp $ */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP
#include <nbcompat.h>
#include <nbcompat/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: mkstemp.c,v 1.4 2004/08/23 03:32:12 jlam Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#if HAVE_NBTOOL_CONFIG_H
#define GETTEMP gettemp
#else
#include <nbcompat/assert.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <nbcompat/stdio.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/unistd.h>
#if 0
#include "reentrant.h"
#include "local.h"
#define GETTEMP __gettemp
#else
#define GETTEMP gettemp
extern int gettemp __P((char *, int *, int));
#endif
#endif
int
mkstemp(path)
char *path;
{
int fd;
_DIAGASSERT(path != NULL);
return (GETTEMP(path, &fd, 0) ? fd : -1);
}
#endif /* !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP */

View File

@@ -0,0 +1,24 @@
BEGIN { process = 1 }
/NBCOMPAT template section follows\./ { process = 0 }
/^\#[ ]*define[ ]+PACKAGE_.*/ {
if (process == 1) {
print "/* " $0 " */";
next;
}
}
/^\#[ ]*define[ ]+/ {
if (process == 1) {
guard = $0;
sub("^#[ ]*define[ ]+", "", guard);
sub("[ ]+.*", "", guard);
print "#ifndef " guard;
print $0;
print "#endif";
next;
}
}
{ print }

View File

@@ -0,0 +1,134 @@
/* $NetBSD: nbcompat.h,v 1.43 2009/04/13 11:30:46 joerg Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <nbcompat/nbconfig.h>
#include <nbcompat/cdefs.h>
#include <nbcompat/types.h>
#include <nbcompat/limits.h>
#include <nbcompat/endian.h>
#include <nbcompat/param.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_STDDEF_H
#include <stddef.h>
#endif
#include <nbcompat/assert.h>
#include <nbcompat/ctype.h>
#include <nbcompat/dirent.h>
#include <nbcompat/err.h>
#include <nbcompat/fnmatch.h>
#include <nbcompat/grp.h>
#include <nbcompat/paths.h>
#include <nbcompat/pwd.h>
#include <nbcompat/queue.h>
#include <nbcompat/stat.h>
#include <nbcompat/statvfs.h>
#include <nbcompat/stdlib.h>
#include <nbcompat/stdio.h>
#include <nbcompat/string.h>
#include <nbcompat/termcap.h>
#include <nbcompat/time.h>
#include <nbcompat/tzfile.h>
#include <nbcompat/unistd.h>
#include <nbcompat/util.h>
#if HAVE_NBCOMPAT_POLL
# if HAVE_POLL_H
# undef HAVE_POLL_H
# endif
# if HAVE_SYS_POLL_H
# undef HAVE_SYS_POLL_H
# endif
# include <nbcompat/poll.h>
#endif
#if HAVE_NBCOMPAT_FTS
# if HAVE_FTS_H
# undef HAVE_FTS_H
# endif
# include <nbcompat/fts.h>
#endif
#if HAVE_NBCOMPAT_GLOB
# if HAVE_GLOB_H
# undef HAVE_GLOB_H
# endif
# include <nbcompat/glob.h>
#endif
#if HAVE_NBCOMPAT_REGEX
# if HAVE_REGEX_H
# undef HAVE_REGEX_H
# endif
# include <nbcompat/regex.h>
#endif
#if HAVE_NBCOMPAT_MD5INIT
# if HAVE_MD5_H
# undef HAVE_MD5_H
# endif
#endif
#if HAVE_NBCOMPAT_MD5
# if HAVE_MD5_H
# undef HAVE_MD5_H
# endif
#endif
#if HAVE_NBCOMPAT_RMD160
# if HAVE_RMD160_H
# undef HAVE_RMD160_H
# endif
#endif
#if HAVE_NBCOMPAT_SHA1
# if HAVE_SHA1_H
# undef HAVE_SHA1_H
# endif
#endif
#if HAVE_NBCOMPAT_VIS
# if HAVE_VIS_H
# undef HAVE_VIS_H
# endif
# include <nbcompat/vis.h>
#endif
#if !HAVE_GETOPT_H || !HAVE_STRUCT_OPTION
# undef HAVE_GETOPT_H
# include <nbcompat/getopt.h>
#endif

View File

@@ -0,0 +1,47 @@
/* $NetBSD: assert.h,v 1.2 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_ASSERT_H_
#define _NBCOMPAT_ASSERT_H_
#if HAVE_ASSERT_H
# include <assert.h>
#endif
/*
* Declare macros and functions that may be missing in <assert.h>.
*/
#ifndef _DIAGASSERT
#define _DIAGASSERT(cond) assert(cond)
#endif
#endif /* !_NBCOMPAT_ASSERT_H_ */

View File

@@ -0,0 +1,100 @@
/* $NetBSD: cdefs.h,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_SYS_CDEFS_H_
#define _NBCOMPAT_SYS_CDEFS_H_
#if HAVE_SYS_CDEFS_H
# include <sys/cdefs.h>
#endif
/*
* Declare macros and functions that may be missing in <sys/cdefs.h>.
*/
#ifndef __IDSTRING
# define __IDSTRING(name,string) \
static const char name[] __attribute__((__unused__)) = string
#endif
#ifndef __COPYRIGHT
# define __COPYRIGHT(_s) __IDSTRING(copyright,_s)
#endif
#ifndef __RCSID
# define __RCSID(_s) __IDSTRING(rcsid,_s)
#endif
#ifndef __P
# if defined(__STDC__) || defined(__cplusplus)
# define __P(protos) protos /* full-blown ANSI C */
# else
# define __P(protos) () /* traditional C preprocessor */
# endif
#endif
#ifndef __CONCAT
# if defined(__STDC__) || defined(__cplusplus)
# define __CONCAT(x,y) x ## y
# else
# define __CONCAT(x,y) x/**/y
# endif
#endif
#ifndef __BEGIN_DECLS
# if defined(__cplusplus)
# define __BEGIN_DECLS extern "C" {
# else
# define __BEGIN_DECLS
# endif
#endif
#ifndef __END_DECLS
# if defined(__cplusplus)
# define __END_DECLS };
# else
# define __END_DECLS
# endif
#endif
#ifndef __restrict
/*
* C99 defines the restrict type qualifier keyword, which was made available
* in GCC 2.92.
*/
# if __STDC_VERSION__ >= 199901L
# define __restrict restrict
# else
# define __restrict /* delete __restrict when not supported */
# endif
#endif
#endif /* !_NBCOMPAT_SYS_CDEFS_H_ */

View File

@@ -0,0 +1,665 @@
/* nbcompat/config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define to 1 if the `pread' function is broken. */
#undef BROKEN_PREAD
/* Define to 1 if the `pwrite' function is broken. */
#undef BROKEN_PWRITE
/* Define to 1 if the `getpgrp' function requires zero arguments. */
#undef GETPGRP_VOID
/* Define to 1 if you have the <alloca.h> header file. */
#undef HAVE_ALLOCA_H
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
/* Define to 1 if you have the <assert.h> header file. */
#undef HAVE_ASSERT_H
/* Define to 1 if you have the `bcopy' function. */
#undef HAVE_BCOPY
/* Define to 1 if you have the `bzero' function. */
#undef HAVE_BZERO
/* Define to 1 if you have the <ctype.h> header file. */
#undef HAVE_CTYPE_H
/* Define to 1 if you have the declaration of `endgrent', and to 0 if you
don't. */
#undef HAVE_DECL_ENDGRENT
/* Define to 1 if you have the declaration of `endpwent', and to 0 if you
don't. */
#undef HAVE_DECL_ENDPWENT
/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
*/
#undef HAVE_DECL_OPTARG
/* Define to 1 if you have the declaration of `optind', and to 0 if you don't.
*/
#undef HAVE_DECL_OPTIND
/* Define to 1 if you have the declaration of `optreset', and to 0 if you
don't. */
#undef HAVE_DECL_OPTRESET
/* Define to 1 if you have the declaration of `setpassent', and to 0 if you
don't. */
#undef HAVE_DECL_SETPASSENT
/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
don't. */
#undef HAVE_DECL_SNPRINTF
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
don't. */
#undef HAVE_DECL_STRERROR_R
/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
don't. */
#undef HAVE_DECL_VASPRINTF
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define if dirfd is either a function or a macro. */
#undef HAVE_DIRFD
/* Define to 1 if `dd_fd' is a member of `DIR'. */
#undef HAVE_DIR_DD_FD
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if you have the `err' function. */
#undef HAVE_ERR
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fgetln' function. */
#undef HAVE_FGETLN
/* Define to 1 if you have the `fnmatch' function. */
#undef HAVE_FNMATCH
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `fparseln' function. */
#undef HAVE_FPARSELN
/* Define to 1 if the system has the type `fsid_t'. */
#undef HAVE_FSID_T
/* Define to 1 if you have the <fts.h> header file. */
#undef HAVE_FTS_H
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getenv' function. */
#undef HAVE_GETENV
/* Define to 1 if you have the `getmode' function. */
#undef HAVE_GETMODE
/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO
/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H
/* Define to 1 if you have the `getpassphrase' function. */
#undef HAVE_GETPASSPHRASE
/* Define to 1 if you have the `getpgrp' function. */
#undef HAVE_GETPGRP
/* Define to 1 if you have the `gid_from_group' function. */
#undef HAVE_GID_FROM_GROUP
/* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H
/* Define to 1 if you have the `group_from_gid' function. */
#undef HAVE_GROUP_FROM_GID
/* Define to 1 if you have the <grp.h> header file. */
#undef HAVE_GRP_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `isblank' function. */
#undef HAVE_ISBLANK
/* Define to 1 if you have the `issetugid' function. */
#undef HAVE_ISSETUGID
/* Define to 1 if you have the `lchflags' function. */
#undef HAVE_LCHFLAGS
/* Define to 1 if you have the `lchmod' function. */
#undef HAVE_LCHMOD
/* Define to 1 if you have the `lchown' function. */
#undef HAVE_LCHOWN
/* Define to 1 if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define to 1 if you have the `util' library (-lutil). */
#undef HAVE_LIBUTIL
/* Define to 1 if you have the <libutil.h> header file. */
#undef HAVE_LIBUTIL_H
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if the system has the type `long double'. */
#undef HAVE_LONG_DOUBLE
/* Define to 1 if the system has the type `long long'. */
#undef HAVE_LONG_LONG
/* Define to 1 if you have the `lutimes' function. */
#undef HAVE_LUTIMES
/* Define to 1 if you have the <machine/endian.h> header file. */
#undef HAVE_MACHINE_ENDIAN_H
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#undef HAVE_MALLOC
/* Define to 1 if you have the <md5.h> header file. */
#undef HAVE_MD5_H
/* Define to 1 if you have the `memcpy' function. */
#undef HAVE_MEMCPY
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if you have the `mkdtemp' function. */
#undef HAVE_MKDTEMP
/* Define to 1 if you have the `mkstemp' function. */
#undef HAVE_MKSTEMP
/* Define to 1 if the `fts_*' functions are built into the library. */
#undef HAVE_NBCOMPAT_FTS
/* Define to 1 if the `glob' function is built into the library. */
#undef HAVE_NBCOMPAT_GLOB
/* Define to 1 if the `MD5*' functions are built into the library. */
#undef HAVE_NBCOMPAT_MD5
/* Define to 1 if the `MD5Init' function is built into the library. */
#undef HAVE_NBCOMPAT_MD5INIT
/* Define to 1 if the `poll' function is built into the library. */
#undef HAVE_NBCOMPAT_POLL
/* Define to 1 if the `queue' macros are supplied by the library. */
#undef HAVE_NBCOMPAT_QUEUE
/* Define to 1 if the `regex' functions are built into the library. */
#undef HAVE_NBCOMPAT_REGEX
/* Define to 1 if the `RMD160*' functions are built into the library. */
#undef HAVE_NBCOMPAT_RMD160
/* Define to 1 if the `SHA1*' functions are built into the library. */
#undef HAVE_NBCOMPAT_SHA1
/* Define to 1 if the `SHA2*' functions are built into the library. */
#undef HAVE_NBCOMPAT_SHA2
/* Define to 1 if the `vis' function is built into the library. */
#undef HAVE_NBCOMPAT_VIS
/* Define to 1 if you have the <ndir.h> header file. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <paths.h> header file. */
#undef HAVE_PATHS_H
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define to 1 if *printf() uses %qd to print `long long' (otherwise uses
%lld). */
#undef HAVE_PRINTF_QD
/* Define to 1 if you have the `pwcache_groupdb' function. */
#undef HAVE_PWCACHE_GROUPDB
/* Define to 1 if you have the `pwcache_userdb' function. */
#undef HAVE_PWCACHE_USERDB
/* Define to 1 if you have the <pwd.h> header file. */
#undef HAVE_PWD_H
/* Define to 1 if you have the <regex.h> header file. */
#undef HAVE_REGEX_H
/* Define to 1 if you have the <rmd160.h> header file. */
#undef HAVE_RMD160_H
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the `setgroupent' function. */
#undef HAVE_SETGROUPENT
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the `setmode' function. */
#undef HAVE_SETMODE
/* Define to 1 if you have the `setpassent' function. */
#undef HAVE_SETPASSENT
/* Define to 1 if you have the `setprogname' function. */
#undef HAVE_SETPROGNAME
/* Define to 1 if you have the <sha1.h> header file. */
#undef HAVE_SHA1_H
/* Define to 1 if you have the <sha2.h> header file. */
#undef HAVE_SHA2_H
/* Define to 1 if you have the `shquote' function. */
#undef HAVE_SHQUOTE
/* Define to 1 if you have the <signal.h> header file. */
#undef HAVE_SIGNAL_H
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if the system has the type `socklen_t'. */
#undef HAVE_SOCKLEN_T
/* Define to 1 if you have the `statvfs' function. */
#undef HAVE_STATVFS
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the `strerror_r' function. */
#undef HAVE_STRERROR_R
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strmode' function. */
#undef HAVE_STRMODE
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the `strsvis' function. */
#undef HAVE_STRSVIS
/* Define to 1 if you have the `strtoll' function. */
#undef HAVE_STRTOLL
/* Define to 1 if the system has the type `struct addrinfo'. */
#undef HAVE_STRUCT_ADDRINFO
/* Define to 1 if `d_namlen' is a member of `struct dirent'. */
#undef HAVE_STRUCT_DIRENT_D_NAMLEN
/* Define to 1 if the system has the type `struct in6_addr'. */
#undef HAVE_STRUCT_IN6_ADDR
/* Define to 1 if the system has the type `struct option'. */
#undef HAVE_STRUCT_OPTION
/* Define to 1 if the system has the type `struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `f_flags' is a member of `struct statfs'. */
#undef HAVE_STRUCT_STATFS_F_FLAGS
/* Define to 1 if `f_fsize' is a member of `struct statfs'. */
#undef HAVE_STRUCT_STATFS_F_FSIZE
/* Define to 1 if `f_iosize' is a member of `struct statfs'. */
#undef HAVE_STRUCT_STATFS_F_IOSIZE
/* Define to 1 if you have the `strunvis' function. */
#undef HAVE_STRUNVIS
/* Define to 1 if you have the `strvis' function. */
#undef HAVE_STRVIS
/* Define to 1 if you have the `svis' function. */
#undef HAVE_SVIS
/* Define to 1 if you have the <sysexits.h> header file. */
#undef HAVE_SYSEXITS_H
/* Define to 1 if you have the <sys/byteorder.h> header file. */
#undef HAVE_SYS_BYTEORDER_H
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#undef HAVE_SYS_CDEFS_H
/* Define to 1 if you have the <sys/dir.h> header file. */
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/endian.h> header file. */
#undef HAVE_SYS_ENDIAN_H
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define to 1 if you have the <sys/mkdev.h> header file. */
#undef HAVE_SYS_MKDEV_H
/* Define to 1 if you have the <sys/mount.h> header file. */
#undef HAVE_SYS_MOUNT_H
/* Define to 1 if you have the <sys/ndir.h> header file. */
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/poll.h> header file. */
#undef HAVE_SYS_POLL_H
/* Define to 1 if you have the <sys/queue.h> header file. */
#undef HAVE_SYS_QUEUE_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/statfs.h> header file. */
#undef HAVE_SYS_STATFS_H
/* Define to 1 if you have the <sys/statvfs.h> header file. */
#undef HAVE_SYS_STATVFS_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/ttycom.h> header file. */
#undef HAVE_SYS_TTYCOM_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have the <sys/vfs.h> header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have the <termcap.h> header file. */
#undef HAVE_TERMCAP_H
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <tzfile.h> header file. */
#undef HAVE_TZFILE_H
/* Define to 1 if you have the `uid_from_user' function. */
#undef HAVE_UID_FROM_USER
/* Define to 1 if the system has the type `uintptr_t'. */
#undef HAVE_UINTPTR_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the `unvis' function. */
#undef HAVE_UNVIS
/* Define to 1 if you have the `user_from_uid' function. */
#undef HAVE_USER_FROM_UID
/* Define to 1 if you have the `usleep' function. */
#undef HAVE_USLEEP
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to 1 if you have the `utimes' function. */
#undef HAVE_UTIMES
/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H
/* Define to 1 if the `va_copy' function is supported. */
#undef HAVE_VA_COPY
/* Define to 1 if you have the `vfork' function. */
#undef HAVE_VFORK
/* Define to 1 if you have the <vfork.h> header file. */
#undef HAVE_VFORK_H
/* Define to 1 if you have the `vis' function. */
#undef HAVE_VIS
/* Define to 1 if you have the <vis.h> header file. */
#undef HAVE_VIS_H
/* Define to 1 if you have the `vprintf' function. */
#undef HAVE_VPRINTF
/* Define to 1 if you have the `warn' function. */
#undef HAVE_WARN
/* Define to 1 if `fork' works. */
#undef HAVE_WORKING_FORK
/* Define to 1 if `long long' is supported and sizeof(off_t) >= 8. */
#undef HAVE_WORKING_LONG_LONG
/* Define to 1 if `vfork' works. */
#undef HAVE_WORKING_VFORK
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* define if your compiler has __attribute__ */
#undef HAVE___ATTRIBUTE__
/* Define to 1 if the `__builtin_va_copy' function is supported. */
#undef HAVE___BUILTIN_VA_COPY
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if strerror_r returns char *. */
#undef STRERROR_R_CHAR_P
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT32_T
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT64_T
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT8_T
/* Define to the type of a signed integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
#undef int16_t
/* Define to the type of a signed integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef int32_t
/* Define to the type of a signed integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
#undef int64_t
/* Define to the type of a signed integer type of width exactly 8 bits if such
a type exists and the standard includes do not define it. */
#undef int8_t
/* Define to rpl_malloc if the replacement function should be used. */
#undef malloc
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* Define to the type of an unsigned integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
#undef uint16_t
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef uint32_t
/* Define to the type of an unsigned integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
#undef uint64_t
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
#undef uint8_t
/* Define to the type of an unsigned integer type wide enough to hold a
pointer, if such a type exists, and if the system does not define it. */
#undef uintptr_t
/* Define as `fork' if `vfork' does not work. */
#undef vfork
/* NBCOMPAT template section follows. */
#ifndef HAVE___ATTRIBUTE__
# define __attribute__(x)
#endif

View File

@@ -0,0 +1,47 @@
/* $NetBSD: ctype.h,v 1.2 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_CTYPE_H_
#define _NBCOMPAT_CTYPE_H_
#if HAVE_CTYPE_H
# include <ctype.h>
#endif
/*
* Declare macros and functions that may be missing in <ctype.h>.
*/
#if !HAVE_ISBLANK
int isblank(int);
#endif
#endif /* !_NBCOMPAT_CTYPE_H_ */

View File

@@ -0,0 +1,238 @@
/* $NetBSD: db.h,v 1.3 2010/03/03 06:03:45 obache Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)db.h 8.7 (Berkeley) 6/16/94
*/
#ifndef _NBCOMPAT_DB_H_
#define _NBCOMPAT_DB_H_
#include <nbcompat/types.h>
#include <nbcompat/cdefs.h>
#include <nbcompat/limits.h>
#define RET_ERROR -1 /* Return values. */
#define RET_SUCCESS 0
#define RET_SPECIAL 1
/*
* XXX
* SGI/IRIX already has a pgno_t.
*/
#ifdef __sgi
#define pgno_t db_pgno_t
#endif
#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */
typedef uint32_t pgno_t;
#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */
typedef uint16_t indx_t;
#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */
typedef uint32_t recno_t;
/* Key/data structure -- a Data-Base Thang. */
typedef struct {
void *data; /* data */
size_t size; /* data length */
} DBT;
/* Routine flags. */
#define R_CURSOR 1 /* del, put, seq */
#define __R_UNUSED 2 /* UNUSED */
#define R_FIRST 3 /* seq */
#define R_IAFTER 4 /* put (RECNO) */
#define R_IBEFORE 5 /* put (RECNO) */
#define R_LAST 6 /* seq (BTREE, RECNO) */
#define R_NEXT 7 /* seq */
#define R_NOOVERWRITE 8 /* put */
#define R_PREV 9 /* seq (BTREE, RECNO) */
#define R_SETCURSOR 10 /* put (RECNO) */
#define R_RECNOSYNC 11 /* sync (RECNO) */
typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
/*
* !!!
* The following flags are included in the dbopen(3) call as part of the
* open(2) flags. In order to avoid conflicts with the open flags, start
* at the top of the 16 or 32-bit number space and work our way down. If
* the open flags were significantly expanded in the future, it could be
* a problem. Wish I'd left another flags word in the dbopen call.
*
* !!!
* None of this stuff is implemented yet. The only reason that it's here
* is so that the access methods can skip copying the key/data pair when
* the DB_LOCK flag isn't set.
*/
#if UINT_MAX > 65535
#define DB_LOCK 0x20000000 /* Do locking. */
#define DB_SHMEM 0x40000000 /* Use shared memory. */
#define DB_TXN 0x80000000 /* Do transactions. */
#else
#define DB_LOCK 0x2000 /* Do locking. */
#define DB_SHMEM 0x4000 /* Use shared memory. */
#define DB_TXN 0x8000 /* Do transactions. */
#endif
/* Access method description structure. */
typedef struct __db {
DBTYPE type; /* Underlying db type. */
int (*close) (struct __db *);
int (*del) (const struct __db *, const DBT *, unsigned int);
int (*get) (const struct __db *, const DBT *, DBT *, unsigned int);
int (*put) (const struct __db *, DBT *, const DBT *, unsigned int);
int (*seq) (const struct __db *, DBT *, DBT *, unsigned int);
int (*sync) (const struct __db *, unsigned int);
void *internal; /* Access method private. */
int (*fd) (const struct __db *);
} DB;
#define BTREEMAGIC 0x053162
#define BTREEVERSION 3
/* Structure used to pass parameters to the btree routines. */
typedef struct {
#define R_DUP 0x01 /* duplicate keys */
unsigned long flags;
unsigned int cachesize; /* bytes to cache */
int maxkeypage; /* maximum keys per page */
int minkeypage; /* minimum keys per page */
unsigned int psize; /* page size */
int (*compare) /* comparison function */
(const DBT *, const DBT *);
size_t (*prefix) /* prefix function */
(const DBT *, const DBT *);
int lorder; /* byte order */
} BTREEINFO;
#define HASHMAGIC 0x061561
#define HASHVERSION 2
/* Structure used to pass parameters to the hashing routines. */
typedef struct {
unsigned int bsize; /* bucket size */
unsigned int ffactor; /* fill factor */
unsigned int nelem; /* number of elements */
unsigned int cachesize; /* bytes to cache */
uint32_t /* hash function */
(*hash)(const void *, size_t);
int lorder; /* byte order */
} HASHINFO;
/* Structure used to pass parameters to the record routines. */
typedef struct {
#define R_FIXEDLEN 0x01 /* fixed-length records */
#define R_NOKEY 0x02 /* key not required */
#define R_SNAPSHOT 0x04 /* snapshot the input */
unsigned long flags;
unsigned int cachesize; /* bytes to cache */
unsigned int psize; /* page size */
int lorder; /* byte order */
size_t reclen; /* record length (fixed-length records) */
uint8_t bval; /* delimiting byte (variable-length records */
char *bfname; /* btree file name */
} RECNOINFO;
#ifdef __DBINTERFACE_PRIVATE
/*
* Little endian <==> big endian 32-bit swap macros.
* M_32_SWAP swap a memory location
* P_32_SWAP swap a referenced memory location
* P_32_COPY swap from one location to another
*/
#define M_32_SWAP(a) { \
uint32_t _tmp = a; \
((char *)(void *)&a)[0] = ((char *)(void *)&_tmp)[3]; \
((char *)(void *)&a)[1] = ((char *)(void *)&_tmp)[2]; \
((char *)(void *)&a)[2] = ((char *)(void *)&_tmp)[1]; \
((char *)(void *)&a)[3] = ((char *)(void *)&_tmp)[0]; \
}
#define P_32_SWAP(a) { \
char _tmp[4]; \
_tmp[0] = ((char *)(void *)a)[0]; \
_tmp[1] = ((char *)(void *)a)[1]; \
_tmp[2] = ((char *)(void *)a)[2]; \
_tmp[3] = ((char *)(void *)a)[3]; \
((char *)(void *)a)[0] = _tmp[3]; \
((char *)(void *)a)[1] = _tmp[2]; \
((char *)(void *)a)[2] = _tmp[1]; \
((char *)(void *)a)[3] = _tmp[0]; \
}
#define P_32_COPY(a, b) { \
((char *)(void *)&(b))[0] = ((char *)(void *)&(a))[3]; \
((char *)(void *)&(b))[1] = ((char *)(void *)&(a))[2]; \
((char *)(void *)&(b))[2] = ((char *)(void *)&(a))[1]; \
((char *)(void *)&(b))[3] = ((char *)(void *)&(a))[0]; \
}
/*
* Little endian <==> big endian 16-bit swap macros.
* M_16_SWAP swap a memory location
* P_16_SWAP swap a referenced memory location
* P_16_COPY swap from one location to another
*/
#define M_16_SWAP(a) { \
uint16_t _tmp = a; \
((char *)(void *)&a)[0] = ((char *)(void *)&_tmp)[1]; \
((char *)(void *)&a)[1] = ((char *)(void *)&_tmp)[0]; \
}
#define P_16_SWAP(a) { \
char _tmp[2]; \
_tmp[0] = ((char *)(void *)a)[0]; \
_tmp[1] = ((char *)(void *)a)[1]; \
((char *)(void *)a)[0] = _tmp[1]; \
((char *)(void *)a)[1] = _tmp[0]; \
}
#define P_16_COPY(a, b) { \
((char *)(void *)&(b))[0] = ((char *)(void *)&(a))[1]; \
((char *)(void *)&(b))[1] = ((char *)(void *)&(a))[0]; \
}
#endif
__BEGIN_DECLS
DB *dbopen(const char *, int, mode_t, DBTYPE, const void *);
#ifdef __DBINTERFACE_PRIVATE
#ifndef NBBY
#define NBBY 8
#endif
#define _DBMASK(a) (~((1ULL << (sizeof(a) * NBBY)) - 1))
#define _DBFIT(a, t) _DIAGASSERT(((a) & _DBMASK(t)) == 0)
DB *__bt_open(const char *, int, mode_t, const BTREEINFO *, int);
DB *__hash_open(const char *, int, mode_t, const HASHINFO *, int);
DB *__rec_open(const char *, int, mode_t, const RECNOINFO *, int);
void __dbpanic(DB *);
#endif
__END_DECLS
#endif /* !_DB_H_ */

View File

@@ -0,0 +1,58 @@
/* $NetBSD: dirent.h,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_DIRENT_H_
#define _NBCOMPAT_DIRENT_H_
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
/*
* Declare functions and macros that may be missing in <dirent.h>.
*/
#if !defined(HAVE_DIRFD) && defined(HAVE_DIR_DD_FD)
#define dirfd(dirp) ((dirp)->dd_fd)
#endif
#endif /* !_NBCOMPAT_DIRENT_H_ */

View File

@@ -0,0 +1,76 @@
/* $NetBSD: endian.h,v 1.3 2010/01/24 12:41:21 obache Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_ENDIAN_H_
#define _NBCOMPAT_ENDIAN_H_
#if HAVE_ENDIAN_H
# include <endian.h>
#endif
#if HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
#if HAVE_MACHINE_ENDIAN_H
# include <machine/endian.h>
#endif
#if HAVE_SYS_BYTEORDER_H
# include <sys/byteorder.h>
#endif
/*
* Declare macros that may be missing in <endian.h>, <sys/endian.h>,
* <machine/endian.h> and <sys/byteorder.h>
*/
#ifndef LITTLE_ENDIAN
# define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
# define BIG_ENDIAN 4321
#endif
#ifndef BYTE_ORDER
# if defined(_BIG_ENDIAN)
# define BYTE_ORDER BIG_ENDIAN
# elif defined(_LITTE_ENDIAN)
# define BYTE_ORDER LITTLE_ENDIAN
# elif defined(WORDS_BIGENDIAN)
# define BYTE_ORDER BIG_ENDIAN
# else
# define BYTE_ORDER LITTLE_ENDIAN
# endif
#endif
#endif /* !_NBCOMPAT_ENDIAN_H_ */

View File

@@ -0,0 +1,59 @@
/* $NetBSD: err.h,v 1.4 2004/08/23 03:32:13 jlam Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fts.h 8.3 (Berkeley) 8/14/94
*/
#ifndef _NBCOMPAT_ERR_H_
#define _NBCOMPAT_ERR_H_
#if HAVE_ERR_H
# include <err.h>
#endif
#if !HAVE_ERR
void err __P((int, const char *, ...));
void errx __P((int, const char *, ...));
void verr __P((int, const char *, va_list));
void verrx __P((int, const char *, va_list));
#endif
#if !HAVE_WARN
void warn __P((const char *, ...));
void warnx __P((const char *, ...));
void vwarn __P((const char *, va_list));
void vwarnx __P((const char *, va_list));
#endif
#endif /* !_NBCOMPAT_ERR_H_ */

View File

@@ -0,0 +1,54 @@
/* $NetBSD: fnmatch.h,v 1.2 2004/08/10 18:47:55 jlam Exp $ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _NBCOMPAT_FNMATCH_H_
#define _NBCOMPAT_FNMATCH_H_
#if HAVE_FNMATCH_H
# include <fnmatch.h>
#endif
#if !HAVE_FNMATCH
#define FNM_NOMATCH 1 /* Match failed. */
#define FNM_NOSYS 2 /* Function not implemented. */
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
#define FNM_CASEFOLD 0x08 /* Pattern is matched case-insensitive */
#define FNM_LEADING_DIR 0x10 /* Ignore /<tail> after Imatch. */
int fnmatch(const char *, const char *, int);
#endif
#endif /* !_NBCOMPAT_FNMATCH_H_ */

View File

@@ -0,0 +1,131 @@
/* $NetBSD: fts.h,v 1.7 2012/03/01 16:18:51 hans Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fts.h 8.3 (Berkeley) 8/14/94
*/
#ifndef _NBCOMPAT_FTS_H_
#define _NBCOMPAT_FTS_H_
typedef struct {
struct _ftsent *fts_cur; /* current node */
struct _ftsent *fts_child; /* linked list of children */
struct _ftsent **fts_array; /* sort array */
dev_t fts_dev; /* starting device # */
char *fts_path; /* path for this descent */
int fts_rfd; /* fd for root */
unsigned int fts_pathlen; /* sizeof(path) */
unsigned int fts_nitems; /* elements in the sort array */
int (*fts_compar) /* compare function */
(const struct _ftsent **, const struct _ftsent **);
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
#define FTS_LOGICAL 0x002 /* logical walk */
#define FTS_NOCHDIR 0x004 /* don't change directories */
#define FTS_NOSTAT 0x008 /* don't get stat info */
#define FTS_PHYSICAL 0x010 /* physical walk */
#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
#define FTS_XDEV 0x040 /* don't cross devices */
#define FTS_WHITEOUT 0x080 /* return whiteout information */
#define FTS_OPTIONMASK 0x0ff /* valid user option mask */
#define FTS_NAMEONLY 0x100 /* (private) child names only */
#define FTS_STOP 0x200 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
} FTS;
typedef struct _ftsent {
struct _ftsent *fts_cycle; /* cycle node */
struct _ftsent *fts_parent; /* parent directory */
struct _ftsent *fts_link; /* next file in directory */
long fts_number; /* local numeric value */
void *fts_pointer; /* local address value */
char *fts_accpath; /* access path */
char *fts_path; /* root path */
int fts_errno; /* errno for this node */
int fts_symfd; /* fd for symlink */
unsigned short fts_pathlen; /* strlen(fts_path) */
unsigned short fts_namelen; /* strlen(fts_name) */
ino_t fts_ino; /* inode */
dev_t fts_dev; /* device */
#ifdef __LIBC12_SOURCE__
uint16_t fts_nlink; /* link count */
#else
nlink_t fts_nlink; /* link count */
#endif
#define FTS_ROOTPARENTLEVEL -1
#define FTS_ROOTLEVEL 0
short fts_level; /* depth (-1 to N) */
#define FTS_D 1 /* preorder directory */
#define FTS_DC 2 /* directory that causes cycles */
#define FTS_DEFAULT 3 /* none of the above */
#define FTS_DNR 4 /* unreadable directory */
#define FTS_DOT 5 /* dot or dot-dot */
#define FTS_DP 6 /* postorder directory */
#define FTS_ERR 7 /* error; errno is set */
#define FTS_F 8 /* regular file */
#define FTS_INIT 9 /* initialized only */
#define FTS_NS 10 /* stat(2) failed */
#define FTS_NSOK 11 /* no stat(2) requested */
#define FTS_SL 12 /* symbolic link */
#define FTS_SLNONE 13 /* symbolic link without target */
#define FTS_W 14 /* whiteout object */
unsigned short fts_info; /* user flags for FTSENT structure */
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
#define FTS_ISW 0x04 /* this is a whiteout object */
unsigned short fts_flags; /* private flags for FTSENT structure */
#define FTS_AGAIN 1 /* read node again */
#define FTS_FOLLOW 2 /* follow symbolic link */
#define FTS_NOINSTR 3 /* no instructions */
#define FTS_SKIP 4 /* discard node */
unsigned short fts_instr; /* fts_set() instructions */
struct stat *fts_statp; /* stat(2) information */
char fts_name[1]; /* file name */
} FTSENT;
#include <nbcompat/cdefs.h>
__BEGIN_DECLS
FTSENT *fts_children (FTS *, int);
int fts_close (FTS *);
FTS *fts_open (char * const *, int,
int (*)(const FTSENT **, const FTSENT **));
FTSENT *fts_read (FTS *);
int fts_set (FTS *, FTSENT *, int);
__END_DECLS
#endif /* !_NBCOMPAT_FTS_H_ */

View File

@@ -0,0 +1,64 @@
/* $NetBSD: getopt.h,v 1.5 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_GETOPT_H_
#define _NBCOMPAT_GETOPT_H_
#include <nbcompat/cdefs.h>
#include <nbcompat/unistd.h>
/*
* Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
*/
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
__BEGIN_DECLS
int getopt_long (int, char * const *, const char *,
const struct option *, int *);
__END_DECLS
#endif /* !_NBCOMPAT_GETOPT_H_ */

View File

@@ -0,0 +1,88 @@
/* $Id: glob.h,v 1.3 2004/08/16 17:24:57 jlam Exp $ */
/* from NetBSD: glob.h,v 1.13 2001/03/16 21:02:42 christos Exp */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)glob.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _NBCOMPAT_GLOB_H_
#define _NBCOMPAT_GLOB_H_
typedef struct {
int gl_pathc; /* Count of total paths so far. */
int gl_matchc; /* Count of paths matching pattern. */
int gl_offs; /* Reserved at beginning of gl_pathv. */
int gl_flags; /* Copy of flags parameter to glob. */
char **gl_pathv; /* List of paths matching pattern. */
/* Copy of errfunc parameter to glob. */
int (*gl_errfunc)(const char *, int);
/*
* Alternate filesystem access methods for glob; replacement
* versions of closedir(3), readdir(3), opendir(3), stat(2)
* and lstat(2).
*/
void (*gl_closedir)(void *);
struct dirent *(*gl_readdir)(void *);
void *(*gl_opendir)(const char *);
int (*gl_lstat)(const char *, struct stat *);
int (*gl_stat)(const char *, struct stat *);
} glob_t;
#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
#define GLOB_ERR 0x0004 /* Return on error. */
#define GLOB_MARK 0x0008 /* Append / to matching directories. */
#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
#define GLOB_NOSORT 0x0020 /* Don't sort. */
#define GLOB_NOESCAPE 0x1000 /* Disable backslash escaping. */
#define GLOB_NOSPACE (-1) /* Malloc call failed. */
#define GLOB_ABORTED (-2) /* Unignored error. */
#define GLOB_NOMATCH (-3) /* No match, and GLOB_NOCHECK was not set. */
#define GLOB_NOSYS (-4) /* Implementation does not support function. */
#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */
#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
#define GLOB_LIMIT 0x0400 /* Limit memory used by matches to ARG_MAX */
#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */
#define GLOB_QUOTE 0 /* source compatibility */
#define GLOB_ABEND GLOB_ABORTED /* source compatibility */
int glob(const char *, int, int (*)(const char *, int), glob_t *);
void globfree(glob_t *);
#endif /* !_NBCOMPAT_GLOB_H_ */

View File

@@ -0,0 +1,59 @@
/* $NetBSD: grp.h,v 1.3 2008/09/08 20:20:23 joerg Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_GRP_H_
#define _NBCOMPAT_GRP_H_
#if HAVE_GRP_H
# include <grp.h>
#endif
/*
* Declare functions that may be missing in <grp.h>.
*/
#if !HAVE_SETGROUPENT
int setgroupent(int);
#endif
#if !HAVE_GROUP_FROM_GID
const char *group_from_gid(gid_t, int);
#endif
#if !HAVE_GID_FROM_GROUP
int gid_from_group(const char *, gid_t *);
#endif
#if !HAVE_DECL_ENDGRENT
void endgrent(void);
#endif
#endif /* !_NBCOMPAT_GRP_H_ */

View File

@@ -0,0 +1,73 @@
/* $NetBSD: limits.h,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_LIMITS_H_
#define _NBCOMPAT_LIMITS_H_
#if HAVE_LIMITS_H
# include <limits.h>
#endif
/*
* Declare functions and macros that may be missing in <limits.h>.
*/
#ifndef UINT_MAX
# define UINT_MAX 4294967295U
#endif
#if !defined(LLONG_MAX)
# if defined(LONG_LONG_MAX)
# define LLONG_MAX LONG_LONG_MAX
# else
# define LLONG_MAX (0x7fffffffffffffffLL)
# endif
#endif
#if !defined(LLONG_MIN)
# if defined(LONG_LONG_MIN)
# define LLONG_MIN LONG_LONG_MIN
# else
# define LLONG_MIN (-0x7fffffffffffffffLL-1)
# endif
#endif
#if !defined(ULLONG_MAX)
# define ULLONG_MAX (0xffffffffffffffffULL) /* max unsigned long long */
#endif
#ifndef GID_MAX
# define GID_MAX 2147483647U /* max value for a gid_t (2^31-2) */
#endif
#ifndef UID_MAX
# define UID_MAX 2147483647U /* max value for a uid_t (2^31-2) */
#endif
#endif /* !_NBCOMPAT_LIMITS_H_ */

View File

@@ -0,0 +1,56 @@
/* $NetBSD: md5.h,v 1.5 2008/10/08 14:28:14 joerg Exp $ */
/*
* This file is derived from the RSA Data Security, Inc. MD5 Message-Digest
* Algorithm and has been modified by Jason R. Thorpe <thorpej@NetBSD.ORG>
* for portability and formatting.
*/
/*
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD5 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
#ifndef _NBCOMPAT_SYS_MD5_H_
#define _NBCOMPAT_SYS_MD5_H_
#include <nbcompat/types.h>
#define MD5_DIGEST_LENGTH 16
#define MD5_DIGEST_STRING_LENGTH 33
/* MD5 context. */
typedef struct MD5Context {
uint32_t state[4]; /* state (ABCD) */
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
__BEGIN_DECLS
void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, const unsigned char *, unsigned int);
void MD5Final(unsigned char[16], MD5_CTX *);
char *MD5End(MD5_CTX *, char *);
char *MD5File(const char *, char *);
char *MD5Data(const unsigned char *, unsigned int, char *);
__END_DECLS
#endif /* !_NBCOMPAT_SYS_MD5_H_ */

View File

@@ -0,0 +1,103 @@
/* $NetBSD: mpool.h,v 1.1 2008/10/26 12:52:00 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mpool.h 8.2 (Berkeley) 7/14/94
*/
#ifndef _NBCOMPAT_MPOOL_H_
#define _NBCOMPAT_MPOOL_H_
#include <nbcompat/cdefs.h>
#include <nbcompat/queue.h>
/*
* The memory pool scheme is a simple one. Each in-memory page is referenced
* by a bucket which is threaded in up to two of three ways. All active pages
* are threaded on a hash chain (hashed by page number) and an lru chain.
* Inactive pages are threaded on a free chain. Each reference to a memory
* pool is handed an opaque MPOOL cookie which stores all of this information.
*/
#define HASHSIZE 128
#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE)
/* The BKT structures are the elements of the queues. */
typedef struct _bkt {
CIRCLEQ_ENTRY(_bkt) hq; /* hash queue */
CIRCLEQ_ENTRY(_bkt) q; /* lru queue */
void *page; /* page */
pgno_t pgno; /* page number */
#define MPOOL_DIRTY 0x01 /* page needs to be written */
#define MPOOL_PINNED 0x02 /* page is pinned into memory */
uint8_t flags; /* flags */
} BKT;
typedef struct MPOOL {
CIRCLEQ_HEAD(_lqh, _bkt) lqh; /* lru queue head */
/* hash queue array */
CIRCLEQ_HEAD(_hqh, _bkt) hqh[HASHSIZE];
pgno_t curcache; /* current number of cached pages */
pgno_t maxcache; /* max number of cached pages */
pgno_t npages; /* number of pages in the file */
unsigned long pagesize; /* file page size */
int fd; /* file descriptor */
/* page in conversion routine */
void (*pgin)(void *, pgno_t, void *);
/* page out conversion routine */
void (*pgout)(void *, pgno_t, void *);
void *pgcookie; /* cookie for page in/out routines */
#ifdef STATISTICS
unsigned long cachehit;
unsigned long cachemiss;
unsigned long pagealloc;
unsigned long pageflush;
unsigned long pageget;
unsigned long pagenew;
unsigned long pageput;
unsigned long pageread;
unsigned long pagewrite;
#endif
} MPOOL;
__BEGIN_DECLS
MPOOL *mpool_open(void *, int, pgno_t, pgno_t);
void mpool_filter(MPOOL *, void (*)(void *, pgno_t, void *),
void (*)(void *, pgno_t, void *), void *);
void *mpool_new(MPOOL *, pgno_t *);
void *mpool_get(MPOOL *, pgno_t, unsigned int);
int mpool_put(MPOOL *, void *, unsigned int);
int mpool_sync(MPOOL *);
int mpool_close(MPOOL *);
#ifdef STATISTICS
void mpool_stat(MPOOL *);
#endif
__END_DECLS
#endif /* _MPOOL_H_ */

View File

@@ -0,0 +1,77 @@
/* $NetBSD: ndbm.h,v 1.2 2008/10/29 16:39:03 joerg Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ndbm.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _NBCOMPAT_NDBM_H_
#define _NBCOMPAT_NDBM_H_
#include <nbcompat/cdefs.h>
#include <nbcompat/db.h>
/* Map dbm interface onto db(3). */
#define DBM_RDONLY O_RDONLY
/* Flags to dbm_store(). */
#define DBM_INSERT 0
#define DBM_REPLACE 1
/*
* The db(3) support for ndbm(3) always appends this suffix to the
* file name to avoid overwriting the user's original database.
*/
#define DBM_SUFFIX ".db"
typedef struct {
void *dptr;
size_t dsize; /* XPG4.2 */
} datum;
typedef DB DBM;
#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE
__BEGIN_DECLS
void dbm_close(DBM *);
DBM *dbm_open(const char *, int, mode_t);
int dbm_error(DBM *);
int dbm_clearerr(DBM *);
int dbm_dirfno(DBM *);
int dbm_delete(DBM *, datum);
datum dbm_fetch(DBM *, datum);
datum dbm_firstkey(DBM *);
datum dbm_nextkey(DBM *);
int dbm_store(DBM *, datum, datum, int);
__END_DECLS
#endif /* !_NDBM_H_ */

View File

@@ -0,0 +1,187 @@
/* $Id: netdb.h,v 1.1 2008/10/06 12:36:20 joerg Exp $ */
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Pseudo-implementation of RFC2553 name / address resolution functions
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For example, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#ifndef _NBCOMPAT_NETDB_H
#define _NBCOMPAT_NETDB_H
#include <sys/types.h>
#if defined(HAVE_NETDB_H)
# include <netdb.h>
#endif
#if defined(HAVE_SYS_SOCKET_H)
# include <sys/socket.h>
#endif
/*
* First, socket and INET6 related definitions
*/
#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
# define _SS_MAXSIZE 128 /* Implementation specific max size */
# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
struct sockaddr_storage {
struct sockaddr ss_sa;
char __ss_pad2[_SS_PADSIZE];
};
# define ss_family ss_sa.sa_family
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
#ifndef IN6_IS_ADDR_LOOPBACK
# define IN6_IS_ADDR_LOOPBACK(a) \
(((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \
((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == htonl(1))
#endif /* !IN6_IS_ADDR_LOOPBACK */
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \
(((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \
((uint32_t *)(a))[2] == ntohl(0x0000ffff))
#endif
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#ifndef HAVE_SOCKLEN_T
typedef unsigned int socklen_t;
#endif
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
uint8_t s6_addr[16];
};
#endif /* !HAVE_STRUCT_IN6_ADDR */
#ifndef HAVE_STRUCT_SOCKADDR_IN6
struct sockaddr_in6 {
unsigned short sin6_family;
uint16_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
#ifndef AF_INET6
/* Define it to something that should never appear */
#define AF_INET6 AF_MAX
#endif
/*
* Next, RFC2553 name / address resolution API
*/
#ifndef NI_NUMERICHOST
# define NI_NUMERICHOST (1)
#endif
#ifndef NI_NAMEREQD
# define NI_NAMEREQD (1<<1)
#endif
#ifndef NI_NUMERICSERV
# define NI_NUMERICSERV (1<<2)
#endif
#ifndef AI_PASSIVE
# define AI_PASSIVE (1)
#endif
#ifndef AI_CANONNAME
# define AI_CANONNAME (1<<1)
#endif
#ifndef AI_NUMERICHOST
# define AI_NUMERICHOST (1<<2)
#endif
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif /* !NI_MAXSERV */
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif /* !NI_MAXHOST */
#ifndef EAI_NODATA
# define EAI_NODATA (INT_MAX - 1)
#endif
#ifndef EAI_MEMORY
# define EAI_MEMORY (INT_MAX - 2)
#endif
#ifndef EAI_NONAME
# define EAI_NONAME (INT_MAX - 3)
#endif
#ifndef EAI_SYSTEM
# define EAI_SYSTEM (INT_MAX - 4)
#endif
#ifndef EAI_FAMILY
# define EAI_FAMILY (INT_MAX - 5)
#endif
#ifndef EAI_AGAIN
# define EAI_AGAIN (INT_MAX - 6)
#endif
#ifndef EAI_FAIL
# define EAI_FAIL (INT_MAX - 7)
#endif
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
#endif /* !HAVE_STRUCT_ADDRINFO */
#ifndef HAVE_GETADDRINFO
void freeaddrinfo(struct addrinfo *);
int getaddrinfo(const char *, const char *,
const struct addrinfo *, struct addrinfo **);
#endif /* !HAVE_GETADDRINFO */
#if !defined(HAVE_GAI_STRERROR)
char *gai_strerror(int);
#endif /* !HAVE_GAI_STRERROR */
#ifndef HAVE_GETNAMEINFO
int getnameinfo(const struct sockaddr *, size_t, char *, size_t,
char *, size_t, int);
#endif /* !HAVE_GETNAMEINFO */
#endif /* !_FAKE_RFC2553_H */

View File

@@ -0,0 +1,55 @@
/* $NetBSD: param.h,v 1.3 2009/02/19 00:51:12 abs Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_SYS_PARAM_H_
#define _NBCOMPAT_SYS_PARAM_H_
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
/*
* Declare macros and functions that may be missing in <sys/param.h>.
*/
#if !defined(MIN)
# define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#if !defined(MAX)
# define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif
/* At least Ubuntu 8.10 jumps through hoops to *undefine* ARG_MAX */
#if !defined(ARG_MAX)
# define ARG_MAX sysconf(_SC_ARG_MAX)
#endif
#endif /* !_NBCOMPAT_SYS_PARAM_H_ */

View File

@@ -0,0 +1,58 @@
/* $NetBSD: paths.h,v 1.2 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Johnny C. Lam.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_PATHS_H_
#define _NBCOMPAT_PATHS_H_
#if HAVE_PATHS_H
# include <paths.h>
#endif
/*
* Declare functions and macros that may be missing in <paths.h>.
*/
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif
#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif
#ifndef _PATH_DEFTAPE
# ifdef DEFTAPE
# define _PATH_DEFTAPE DEFTAPE
# else
# define _PATH_DEFTAPE "/dev/tape"
# endif /* DEFTAPE */
#endif /* _PATH_DEFTAPE */
#endif /* !_NBCOMPAT_PATHS_H_ */

View File

@@ -0,0 +1,65 @@
/* $NetBSD: poll.h,v 1.3 2008/04/29 05:46:08 martin Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NBCOMPAT_POLL_H_
#define _NBCOMPAT_POLL_H_
typedef unsigned int nfds_t;
struct pollfd {
int fd; /* file descriptor */
short events; /* events to look for */
short revents; /* events returned */
};
/*
* Testable events (may be specified in events field).
*/
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLRDNORM 0x0040
#define POLLWRNORM POLLOUT
#define POLLRDBAND 0x0080
#define POLLWRBAND 0x0100
/*
* Non-testable events (may not be specified in events field).
*/
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
__BEGIN_DECLS
int poll (struct pollfd *, nfds_t, int);
__END_DECLS
#endif /* !_NBCOMPAT_POLL_H_ */

Some files were not shown because too many files have changed in this diff Show More