mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Compare commits
432
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb8c0f2de5 | ||
|
|
8dad333dce | ||
|
|
ebc53fbed0 | ||
|
|
555f3a396a | ||
|
|
914d9d7bdf | ||
|
|
a66067befe | ||
|
|
0793d3483a | ||
|
|
8ebd0a71be | ||
|
|
6d5cbf7b35 | ||
|
|
fd86137937 | ||
|
|
1d8dc4293f | ||
|
|
f2f7f9e665 | ||
|
|
bbed653cda | ||
|
|
eb63bdd072 | ||
|
|
522548fb47 | ||
|
|
97aa195cf7 | ||
|
|
9b29e6f7a3 | ||
|
|
aeb72b1622 | ||
|
|
285a3eee46 | ||
|
|
c43b8c4bea | ||
|
|
c59928df4d | ||
|
|
af8488a871 | ||
|
|
bc8789b942 | ||
|
|
069aa63891 | ||
|
|
44534645d6 | ||
|
|
9399579574 | ||
|
|
6f0017d1cd | ||
|
|
b6e9b25ba8 | ||
|
|
b8aec9fa1a | ||
|
|
13bc775dc3 | ||
|
|
5f3d5c2bbb | ||
|
|
d99d7e2644 | ||
|
|
7176f4e4b5 | ||
|
|
b17178fc56 | ||
|
|
da128169aa | ||
|
|
294897f4a6 | ||
|
|
d008bcf32c | ||
|
|
4984f343aa | ||
|
|
02ac66c50d | ||
|
|
d94d8f2a59 | ||
|
|
72d8cdf09d | ||
|
|
22930c9bf2 | ||
|
|
7410183b8b | ||
|
|
02859f472b | ||
|
|
a2e1b046f6 | ||
|
|
c4b7291877 | ||
|
|
85f4084001 | ||
|
|
7974fe2117 | ||
|
|
fb8e70d6dd | ||
|
|
67f27f3a02 | ||
|
|
9418ccede9 | ||
|
|
6df1b2474a | ||
|
|
71733723fb | ||
|
|
fc4026d8e4 | ||
|
|
0a95f04d06 | ||
|
|
be7e3b7e7e | ||
|
|
e0f09b6b2a | ||
|
|
2114e10acb | ||
|
|
975320984b | ||
|
|
e3fa2641f4 | ||
|
|
567676ff81 | ||
|
|
8ef76445e8 | ||
|
|
f94a3574d5 | ||
|
|
755f55b0db | ||
|
|
8882961f38 | ||
|
|
5ca8c0ba63 | ||
|
|
102800e09d | ||
|
|
293e360a25 | ||
|
|
d277428889 | ||
|
|
2cb7465b38 | ||
|
|
05be689b57 | ||
|
|
faf92f2a62 | ||
|
|
6a7169a509 | ||
|
|
26bd65c364 | ||
|
|
a4e2c88cf4 | ||
|
|
3be01400fd | ||
|
|
65bf5fa317 | ||
|
|
9b8a44cd18 | ||
|
|
d72d8b1328 | ||
|
|
25b86c05c3 | ||
|
|
787e4db95c | ||
|
|
c994299d50 | ||
|
|
a4219bc4c0 | ||
|
|
0c7b844d25 | ||
|
|
53525291ae | ||
|
|
756245d743 | ||
|
|
7353787873 | ||
|
|
1ff0303078 | ||
|
|
edbba60a5e | ||
|
|
034ff8def9 | ||
|
|
196980f511 | ||
|
|
77a58cad3f | ||
|
|
b5a08c5aca | ||
|
|
ba848785bb | ||
|
|
c13a4f3dbd | ||
|
|
99cf7e3eba | ||
|
|
683158e0c4 | ||
|
|
0fe4e55291 | ||
|
|
376fd36e2d | ||
|
|
8e2e98a2a9 | ||
|
|
b2518f55c0 | ||
|
|
b7843ea9ff | ||
|
|
1ed0083ca9 | ||
|
|
f45e34fcae | ||
|
|
cbd3dceb39 | ||
|
|
fbaad1494f | ||
|
|
f44820454c | ||
|
|
42d2676e7c | ||
|
|
1a3a58fd76 | ||
|
|
91c7b85dc8 | ||
|
|
054cc4cc38 | ||
|
|
96aa2d94a2 | ||
|
|
a5a81fecc7 | ||
|
|
4cb202902d | ||
|
|
8738e7f8b0 | ||
|
|
ec967c06ac | ||
|
|
2ede96c936 | ||
|
|
9199ec6eb2 | ||
|
|
accc07a981 | ||
|
|
75914335da | ||
|
|
d7435cd836 | ||
|
|
7606603541 | ||
|
|
f535a036af | ||
|
|
094bacdbd8 | ||
|
|
86d2c878ac | ||
|
|
51093422b2 | ||
|
|
f797c38303 | ||
|
|
e380bf6248 | ||
|
|
853f0eead1 | ||
|
|
27cc33c3b4 | ||
|
|
80b55d320b | ||
|
|
3bbceb1287 | ||
|
|
3e2ee7271d | ||
|
|
f094496c12 | ||
|
|
bf899faa49 | ||
|
|
29370ca488 | ||
|
|
efc755b282 | ||
|
|
4133498776 | ||
|
|
c14e4c326d | ||
|
|
f44f9c33df | ||
|
|
ff9bef7f88 | ||
|
|
03a7582576 | ||
|
|
e97ec51d01 | ||
|
|
21ee716616 | ||
|
|
1d234146c0 | ||
|
|
580c1888be | ||
|
|
4d049a8baa | ||
|
|
cabcc273c2 | ||
|
|
f2149f697a | ||
|
|
b3a59f408e | ||
|
|
0700dfa143 | ||
|
|
cb2f05ed72 | ||
|
|
d17e960c2b | ||
|
|
deab9deadc | ||
|
|
10fd03c601 | ||
|
|
c90514fc98 | ||
|
|
32a392b61c | ||
|
|
924b9ff68d | ||
|
|
2948fc64a6 | ||
|
|
6cab5056c4 | ||
|
|
8f5ca04bc7 | ||
|
|
5d82cf5c55 | ||
|
|
db65048bb3 | ||
|
|
8e3cc80f6d | ||
|
|
b122c7038e | ||
|
|
80fd73873b | ||
|
|
6a76c11515 | ||
|
|
57aefafe56 | ||
|
|
5f77086119 | ||
|
|
879bf2e65a | ||
|
|
41cfadd63c | ||
|
|
24906b43b9 | ||
|
|
91f62ce6b5 | ||
|
|
889fd48ef9 | ||
|
|
3ec41e0302 | ||
|
|
f94f8067b1 | ||
|
|
3f33a4ce76 | ||
|
|
ea03559a9d | ||
|
|
c709e372e8 | ||
|
|
11c981a96d | ||
|
|
e11c394911 | ||
|
|
969705cc5b | ||
|
|
c12d1df0f0 | ||
|
|
a5570f62dd | ||
|
|
193bd2ce37 | ||
|
|
10b40b115c | ||
|
|
0324daa005 | ||
|
|
600927014b | ||
|
|
bf40c56f1a | ||
|
|
c22164805d | ||
|
|
aa9109070f | ||
|
|
e537c55ea9 | ||
|
|
60478656fa | ||
|
|
9fd18b6c1b | ||
|
|
7a770247ab | ||
|
|
eef089c2ab | ||
|
|
c043db7a2a | ||
|
|
a36e4c9f7b | ||
|
|
287fbbe72e | ||
|
|
f87cd5a229 | ||
|
|
c64908b01f | ||
|
|
99291e9c19 | ||
|
|
d2f5be2a12 | ||
|
|
d586354e51 | ||
|
|
cbf48a6ba0 | ||
|
|
1571a01695 | ||
|
|
f405bed5ef | ||
|
|
44c8d1a2a8 | ||
|
|
e3726b056b | ||
|
|
a993273c0d | ||
|
|
18926cf415 | ||
|
|
9e865adecf | ||
|
|
7752137a6a | ||
|
|
3cf595e562 | ||
|
|
207eb76afb | ||
|
|
537257ae0f | ||
|
|
86fe2915bb | ||
|
|
a4bb25890d | ||
|
|
3fe9de0da5 | ||
|
|
191abc516c | ||
|
|
2f85f8807d | ||
|
|
d144e1d29e | ||
|
|
b88269329c | ||
|
|
54da5be39c | ||
|
|
047f282dd7 | ||
|
|
76894e2e6a | ||
|
|
46bdf16bf7 | ||
|
|
995069eea6 | ||
|
|
6c1b5ea4c1 | ||
|
|
527fbc2a8c | ||
|
|
5dedb8013e | ||
|
|
3de5ea654c | ||
|
|
a88363fbc7 | ||
|
|
b25c5d66b2 | ||
|
|
99a9e88e55 | ||
|
|
5e98d83c10 | ||
|
|
de9ba9bd56 | ||
|
|
2765963bdc | ||
|
|
6c685ebb79 | ||
|
|
507fcb753b | ||
|
|
ad738d03ae | ||
|
|
221c50840f | ||
|
|
b8dc6a10ee | ||
|
|
4e1bac76a8 | ||
|
|
3d61b63cc7 | ||
|
|
958f803fc0 | ||
|
|
9f2233e81a | ||
|
|
9e63357e18 | ||
|
|
49633efbcc | ||
|
|
ff48a63c86 | ||
|
|
4356cfd7ad | ||
|
|
874f1b9bd8 | ||
|
|
51813e8065 | ||
|
|
d7e16e9e83 | ||
|
|
680469021c | ||
|
|
9c9022dd4f | ||
|
|
08d5417a6f | ||
|
|
24e0f77bc6 | ||
|
|
587dbc6fe8 | ||
|
|
439d1d4560 | ||
|
|
0bf9d0eb2b | ||
|
|
584de3b9d6 | ||
|
|
620ce2509a | ||
|
|
ac00263ea0 | ||
|
|
e09675ddfb | ||
|
|
787429e3f0 | ||
|
|
9a70fcabea | ||
|
|
d819080cba | ||
|
|
1f4a4317e1 | ||
|
|
e7233b09e9 | ||
|
|
dbd71bf2c2 | ||
|
|
487253ea1f | ||
|
|
b1099b2fba | ||
|
|
dae3ee4698 | ||
|
|
d6e2f671f7 | ||
|
|
5e75b23212 | ||
|
|
57ba525e34 | ||
|
|
df2a0c93b3 | ||
|
|
882087b96b | ||
|
|
0e7725ccd8 | ||
|
|
bddb308102 | ||
|
|
1a2df358c8 | ||
|
|
f2b0f935d7 | ||
|
|
5bf62f2d3a | ||
|
|
75598ca67e | ||
|
|
ded291197c | ||
|
|
a1a9d21596 | ||
|
|
4174072112 | ||
|
|
1577cd4796 | ||
|
|
6f6ce652f0 | ||
|
|
58581baf02 | ||
|
|
7cc645ed27 | ||
|
|
074d099ee3 | ||
|
|
cc2f1c49e9 | ||
|
|
a692d00365 | ||
|
|
78732ba807 | ||
|
|
c2e14186db | ||
|
|
1273f3e0d1 | ||
|
|
3b5a810700 | ||
|
|
22cbb717d9 | ||
|
|
a2fe9c76a9 | ||
|
|
2b83a2a4d9 | ||
|
|
4f6dc78a92 | ||
|
|
7ae3680842 | ||
|
|
74aa5ce576 | ||
|
|
af92ce7e82 | ||
|
|
b7976c00ed | ||
|
|
1f6a1abf7d | ||
|
|
2a504a34bf | ||
|
|
5f5ab9533b | ||
|
|
63deb0e4e7 | ||
|
|
7e0e6f5007 | ||
|
|
99b306dc44 | ||
|
|
87220b3563 | ||
|
|
1d26b22c83 | ||
|
|
8b7e7ff3ee | ||
|
|
273d56ce89 | ||
|
|
421f82e5cc | ||
|
|
0fb807c1db | ||
|
|
1f1c1b2bb5 | ||
|
|
e4448b6f58 | ||
|
|
d66e34cd42 | ||
|
|
08162fa888 | ||
|
|
b7eb844540 | ||
|
|
2bda74bad3 | ||
|
|
a026e6951d | ||
|
|
1076fc3f18 | ||
|
|
820bd50cfb | ||
|
|
5c03f2d8ec | ||
|
|
10ceac89f9 | ||
|
|
03c5716f9b | ||
|
|
9266597a3c | ||
|
|
8b575de1c6 | ||
|
|
103c293fb6 | ||
|
|
bf3ccd1ae4 | ||
|
|
11872325e2 | ||
|
|
b96bdcd7d9 | ||
|
|
11d90def8c | ||
|
|
67be1ecfe5 | ||
|
|
f4153e135a | ||
|
|
0ac2e7d88b | ||
|
|
82d00cabd4 | ||
|
|
b948be77ef | ||
|
|
d02907df8e | ||
|
|
65b3cbcba7 | ||
|
|
2657da50f0 | ||
|
|
5fa2588651 | ||
|
|
e0585da111 | ||
|
|
fc40c039a4 | ||
|
|
d619f2a8a7 | ||
|
|
fa21d69305 | ||
|
|
77162807d7 | ||
|
|
dfd5ddb713 | ||
|
|
dce38123d0 | ||
|
|
eb712cf192 | ||
|
|
e215c4786c | ||
|
|
335aa3209b | ||
|
|
6e33fad374 | ||
|
|
6432a7793f | ||
|
|
53afa8d967 | ||
|
|
217d85b9c8 | ||
|
|
8c0dc19cc6 | ||
|
|
6aa8372e16 | ||
|
|
883bc19b7c | ||
|
|
8ab69eb330 | ||
|
|
73fbb9a523 | ||
|
|
f799c39b2e | ||
|
|
e627021e1b | ||
|
|
c0fef53b1e | ||
|
|
4bca5a35b8 | ||
|
|
fa0ad20487 | ||
|
|
45b28a8f0b | ||
|
|
c4bf5a3e9a | ||
|
|
e607b492e5 | ||
|
|
193ce8dcd6 | ||
|
|
2f8033d606 | ||
|
|
5de9ba232c | ||
|
|
0a64805148 | ||
|
|
67188fe6b0 | ||
|
|
b1f1136175 | ||
|
|
ea7d993862 | ||
|
|
a9df882945 | ||
|
|
c316b48636 | ||
|
|
342414a6e0 | ||
|
|
1474b80f01 | ||
|
|
d365fd2cfa | ||
|
|
a04e740593 | ||
|
|
3ef21326e9 | ||
|
|
1b8145845f | ||
|
|
dd02efa5f5 | ||
|
|
49e522bfb8 | ||
|
|
6bf028786c | ||
|
|
4788ab4637 | ||
|
|
1e9dc0393c | ||
|
|
be69ea41eb | ||
|
|
a38f13baf0 | ||
|
|
693e7b964f | ||
|
|
68b3ef49b9 | ||
|
|
04282ed1dd | ||
|
|
b3fe135050 | ||
|
|
61cd9516c2 | ||
|
|
c45e5aa9a4 | ||
|
|
f0bf9cb92c | ||
|
|
67a3a8ac7f | ||
|
|
51f7530228 | ||
|
|
01a36ad307 | ||
|
|
4ca6860994 | ||
|
|
7782ca54e1 | ||
|
|
66e3dda448 | ||
|
|
424f8c09fa | ||
|
|
a2cafe309c | ||
|
|
cfe33fd938 | ||
|
|
ece07193c7 | ||
|
|
c21ec3268d | ||
|
|
98fa1d6e73 | ||
|
|
40deae0847 | ||
|
|
ff3d7ed36a | ||
|
|
d8cc5f0c6a | ||
|
|
df4999e1af | ||
|
|
29b687bd18 | ||
|
|
06c48879d8 | ||
|
|
eded85e01e | ||
|
|
5638ea42cb | ||
|
|
127b3c3596 | ||
|
|
134c123619 | ||
|
|
222c4e717a | ||
|
|
feebe869ae | ||
|
|
6c2f050742 | ||
|
|
2863511535 | ||
|
|
797fa6204a | ||
|
|
933e73facc | ||
|
|
6408bdde65 |
+3
-1
@@ -5,8 +5,10 @@ glibc-*
|
||||
|
||||
configparms
|
||||
|
||||
sun4 i386 i386-gnuelf hp300-netbsd hp300
|
||||
sun[43]* i[345]86* hp300*
|
||||
|
||||
ieeetest hppa-sysdeps regex
|
||||
|
||||
gpl2lgpl.sed
|
||||
distinfo
|
||||
distinfo
|
||||
|
||||
+2670
File diff suppressed because it is too large
Load Diff
+3742
File diff suppressed because it is too large
Load Diff
+1644
File diff suppressed because it is too large
Load Diff
+2324
File diff suppressed because it is too large
Load Diff
@@ -167,7 +167,7 @@ subdirs := $(filter-out crypt,$(subdirs))
|
||||
define autoconf-it
|
||||
autoconf $(ACFLAGS) $< > $@.new
|
||||
mv -f $@.new $@
|
||||
test -d CVS && cvs commit -m'Regenerated: autoconf $(ACFLAGS) $<' $@
|
||||
test ! -d CVS || cvs commit -m'Regenerated: autoconf $(ACFLAGS) $<' $@
|
||||
endef
|
||||
|
||||
configure: configure.in; $(autoconf-it)
|
||||
@@ -210,6 +210,7 @@ README: README.template version.c
|
||||
sed -e 's/RELEASE/$(release)/' -e 's/VERSION/$(version)/' < $< > $@
|
||||
# Make it unwritable so I won't change it by mistake.
|
||||
chmod 444 $@
|
||||
test ! -d CVS || commit -m'Remade for $(release)-$(version)' $@
|
||||
|
||||
|
||||
endif # Subdirectory vs. parent makefile
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Make the TAGS files.
|
||||
|
||||
# Copyright (C) 1992, 1994 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -33,9 +33,9 @@ ifeq ($(subdir),ctype)
|
||||
# the header files so tags for optimizing #define's in the
|
||||
# headers won't be put in the tags files, but for ctype,
|
||||
# the functions are just backup for the #define's in the header.
|
||||
tags_sources = $(all-headers) $(all-sources)
|
||||
tags_sources = $(all-headers) $(all-sources) $(all-dist)
|
||||
else # Not ctype.
|
||||
tags_sources = $(all-sources) $(all-headers)
|
||||
tags_sources = $(all-sources) $(all-headers) $(all-dist)
|
||||
endif # ctype
|
||||
endif # No tags_sources
|
||||
|
||||
@@ -43,7 +43,8 @@ sysdep-dirs := $(addprefix $(sysdep_dir)/,$(sysdirs))
|
||||
|
||||
ifndef sysdep_dirs
|
||||
# Find all sysdep directories.
|
||||
sysdep_dirs := $(shell find $(..)sysdeps -type d ! -name RCS -print)
|
||||
sysdep_dirs := $(shell find $(..)sysdeps -type d \
|
||||
! -name RCS ! -name CVS -print)
|
||||
endif
|
||||
|
||||
# Find all sysdep dirs there are, but putting the ones
|
||||
@@ -53,6 +54,11 @@ all-dirs := $(objdir) \
|
||||
$(source_dirs) \
|
||||
$(filter-out $(sysdep-dirs),$(sysdep_dirs))
|
||||
|
||||
vpath %.h $(all-dirs)
|
||||
vpath %.c $(all-dirs)
|
||||
vpath %.S $(all-dirs)
|
||||
vpath %.s $(all-dirs)
|
||||
|
||||
# Find all the subdirs there are, but putting the ones
|
||||
# we are configured to use first and preserving their order.
|
||||
ifndef subdir
|
||||
@@ -67,20 +73,25 @@ all-dist = $(foreach Dist,$(wildcard $(all-dirs:%=%/Dist)),\
|
||||
$(filter %.c %.h %.S %.s,\
|
||||
$(shell cat $(Dist)))))
|
||||
tags_sources = $(all-sources) $(all-headers) $(all-dist)
|
||||
else
|
||||
all-dist = $(distribute)
|
||||
endif
|
||||
|
||||
sources += $(filter %.c %.s %.S,$(all-dist))
|
||||
headers += $(filter %.h,$(all-dist))
|
||||
all-dist := $(filter-out %.h %.c %.s %.S,$(all-dist))
|
||||
|
||||
# All different versions of $(sources), preserving the configured sysdep
|
||||
# directory order.
|
||||
all-sources = $(wildcard $(foreach file,$(sources),\
|
||||
$(file) \
|
||||
$(foreach dir,$(all-dirs),\
|
||||
$(dir)/$(file) \
|
||||
$(dir)/$(file:.c=.S) \
|
||||
$(dir)/$(file:.c=.s))))
|
||||
all-sources = $(shell find . $(all-dirs) -maxdepth 1 \( -name fnord \
|
||||
$(foreach file,$(sort $(sources) $(sources:.c=.S) \
|
||||
$(sources:.c=.s)),\
|
||||
-o -name $(file)) \
|
||||
\) -print)
|
||||
|
||||
all-headers = $(wildcard $(foreach file,$(headers),\
|
||||
$(file) \
|
||||
$(foreach dir,$(all-dirs),$(dir)/$(file))))
|
||||
all-headers = $(shell find . $(all-dirs) -maxdepth 1 \( -name fnord \
|
||||
$(foreach file,$(headers),-o -name $(file)) \
|
||||
\) -print)
|
||||
|
||||
tags_sources := $(strip $(tags_sources))
|
||||
|
||||
|
||||
+135
-21
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -56,7 +56,7 @@ objdir = $(ARCH)
|
||||
endif
|
||||
endif
|
||||
|
||||
# $(common-objdir) is the place to put objects and
|
||||
# $(common-objdir) is the place to put objects and
|
||||
# such that are not specific to a single subdir.
|
||||
ifdef objdir
|
||||
objpfx = $(objdir)/
|
||||
@@ -74,17 +74,25 @@ common-objdir = .
|
||||
endif
|
||||
endif
|
||||
|
||||
libc.a = $(common-objpfx)libc.a
|
||||
|
||||
|
||||
# Get the values defined by options to `configure'.
|
||||
include $(common-objpfx)config.make
|
||||
|
||||
# Run config.status to update config.make and config.h. We don't show the
|
||||
# dependence of config.h to Make, because it is only touched when it
|
||||
# changes and so config.status would be run every time; the dependence of
|
||||
# config.make should suffice to force regeneration and re-exec, and the new
|
||||
# image will notice if config.h changed.
|
||||
$(common-objpfx)config.make: $(common-objpfx)config.status
|
||||
cd $(<D); $(SHELL) $(<F)
|
||||
|
||||
# Force the user to configure before making.
|
||||
$(common-objpfx)config.make:
|
||||
@echo The GNU C library has not been configured. >&2
|
||||
@echo Run \`configure\' to configure it before building. >&2
|
||||
@exit 1
|
||||
$(common-objpfx)config.status: $(..)configure
|
||||
@cd $(@D); if test -f $(@F); then exec $(SHELL) $(@F) --recheck; else \
|
||||
echo The GNU C library has not been configured. >&2; \
|
||||
echo Run \`configure\' to configure it before building. >&2; \
|
||||
echo Try \`configure --help\' for more details. >&2; \
|
||||
exit 1; fi
|
||||
|
||||
# Get the user's configuration parameters.
|
||||
ifneq ($(wildcard $(..)configparms),)
|
||||
@@ -106,13 +114,19 @@ export sysdep_dir := $(sysdep_dir)
|
||||
####
|
||||
|
||||
|
||||
# Set this to either `stdio' or `libio', to compile in either GNU stdio
|
||||
# or GNU libio.
|
||||
ifndef stdio
|
||||
stdio = stdio
|
||||
endif
|
||||
|
||||
# Common prefix for machine-independent installation directories.
|
||||
ifndef prefix
|
||||
ifeq ($(origin prefix),undefined) # ifndef would override explicit empty value.
|
||||
prefix = /usr/local
|
||||
endif
|
||||
|
||||
# Common prefix for machine-dependent installation directories.
|
||||
ifndef exec_prefix
|
||||
ifeq ($(origin exec_prefix),undefined)
|
||||
exec_prefix = $(prefix)
|
||||
endif
|
||||
|
||||
@@ -121,11 +135,16 @@ ifndef libdir
|
||||
libdir = $(exec_prefix)/lib
|
||||
endif
|
||||
|
||||
# Where to install the shared library and dynamic linker.
|
||||
ifndef slibdir
|
||||
slibdir = $(exec_prefix)/lib
|
||||
endif
|
||||
|
||||
# Prefix to put on files installed in $(libdir). For libraries `libNAME.a',
|
||||
# the prefix is spliced between `lib' and the name, so the linker switch
|
||||
# `-l$(libprefix)NAME' finds the library; for other files the prefix is
|
||||
# just prepended to the whole file name.
|
||||
ifndef libprefix
|
||||
ifeq ($(origin libprefix),undefined)
|
||||
libprefix =
|
||||
endif
|
||||
|
||||
@@ -135,7 +154,7 @@ includedir = $(exec_prefix)/include
|
||||
endif
|
||||
|
||||
# Where to install machine-independent data files.
|
||||
# These are the timezone database, and eventually the locale database.
|
||||
# These are the timezone database, and the locale database.
|
||||
ifndef datadir
|
||||
datadir = $(prefix)/share
|
||||
endif
|
||||
@@ -145,6 +164,18 @@ ifndef zonedir
|
||||
zonedir = $(datadir)/zoneinfo
|
||||
endif
|
||||
|
||||
# Where to install the locale and message catalog data files (which are
|
||||
# machine-independent).
|
||||
ifndef localedir
|
||||
localedir = $(datadir)/locale
|
||||
endif
|
||||
|
||||
# Where to install the locale charmap source files.
|
||||
ifndef nlsdir
|
||||
nlsdir = $(datadir)/nls
|
||||
endif
|
||||
|
||||
|
||||
# Where to install programs.
|
||||
ifndef bindir
|
||||
bindir = $(exec_prefix)/bin
|
||||
@@ -247,10 +278,31 @@ endif
|
||||
|
||||
# Command for linking programs with the C library.
|
||||
ifndef +link
|
||||
+link = $(CC) -nostdlib $(LDFLAGS) -o $@ \
|
||||
$(addprefix $(csu-objpfx),start.o $(+preinit)) \
|
||||
$(^:lib=$(libc.a)) $(gnulib) $(libc.a) \
|
||||
$(addprefix $(csu-objpfx),$(+postinit))
|
||||
+link = $(CC) -nostdlib -nostartfiles -o $@ \
|
||||
$(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) \
|
||||
$(addprefix $(csu-objpfx),start.o $(+preinit)) \
|
||||
$(^:$(common-objpfx)libc%=$(link-libc)) \
|
||||
$(addprefix $(csu-objpfx),$(+postinit))
|
||||
endif
|
||||
ifndef config-LDFLAGS
|
||||
ifeq (yes,$(build-shared))
|
||||
config-LDFLAGS = -Wl,-dynamic-linker=$(slibdir)/$(rtld-installed-name)
|
||||
endif
|
||||
endif
|
||||
ifndef link-libc
|
||||
ifeq (yes,$(build-shared))
|
||||
link-libc = -Wl,-rpath-link=$(common-objdir) -Wl,-rpath=$(default-rpath) \
|
||||
$(common-objpfx)libc.so$(libc.so-version) $(gnulib)
|
||||
# Choose the default search path for the dynamic linker based on
|
||||
# where we will install libraries.
|
||||
ifneq ($(libdir),$(slibdir))
|
||||
default-rpath = $(slibdir):$(libdir)
|
||||
else
|
||||
default-rpath = $(libdir)
|
||||
endif
|
||||
else
|
||||
link-libc = $(common-objpfx)libc.a $(gnulib) $(common-objpfx)libc.a
|
||||
endif
|
||||
endif
|
||||
ifndef gnulib
|
||||
gnulib := -lgcc
|
||||
@@ -261,8 +313,31 @@ ifeq ($(elf),yes)
|
||||
endif
|
||||
ifdef objpfx
|
||||
csu-objpfx = $(objpfx)
|
||||
elf-objpfx = $(objpfx)
|
||||
else
|
||||
csu-objpfx = $(..)csu
|
||||
csu-objpfx = $(..)csu/
|
||||
elf-objpfx = $(..)elf/
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
ifndef rtld-installed-name
|
||||
rtld-installed-name = ld.so
|
||||
endif
|
||||
endif
|
||||
|
||||
# How to run a program we just linked with our library.
|
||||
# The program binary is assumed to be $(word 2,$^).
|
||||
built-program-file = $(dir $(word 2,$^))$(notdir $(word 2,$^))
|
||||
ifneq (yes,$(build-shared))
|
||||
built-program-cmd = $(built-program-file)
|
||||
else
|
||||
comma = ,
|
||||
define built-program-cmd
|
||||
LD_LIBRARY_PATH=$(common-objdir)$(patsubst -Wl$(comma)-rpath-link=%,:%,\
|
||||
$(filter -Wl$(comma)-rpath-link=%,\
|
||||
$(sysdep-LDFLAGS))) \
|
||||
$(elf-objpfx)ld.so $(built-program-file)
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef LD
|
||||
@@ -274,7 +349,7 @@ RANLIB = ranlib
|
||||
endif
|
||||
|
||||
# Extra flags to pass to GCC.
|
||||
+gccwarn := -Wall -Wwrite-strings -Wno-parentheses
|
||||
+gccwarn := -Wall -Wwrite-strings -Wno-parentheses -Winline -Wstrict-prototypes
|
||||
|
||||
# This is the program that generates makefile
|
||||
# dependencies from C source files.
|
||||
@@ -336,14 +411,18 @@ endif # gcc
|
||||
# files (including ones given in angle brackets) in the current directory
|
||||
# and in the parent library source directory.
|
||||
# `+sysdep-includes' will be defined by Makerules.
|
||||
+includes = -I. $(filter-out -I,-I$(patsubst %/,%,$(..))) \
|
||||
+includes = -I. $(filter-out -I,-I$(patsubst %/,%,$(..))) $($(stdio)-include) \
|
||||
$(includes) $(+sysdep-includes) $(last-includes)
|
||||
|
||||
# Since libio has several internal header files, we use a -I instead
|
||||
# of many little headers in the top level source directory.
|
||||
libio-include = -I$(..)libio
|
||||
|
||||
# These are the variables that the implicit compilation rules use.
|
||||
CPPFLAGS = $(+includes) $(defines) -include $(..)libc-symbols.h \
|
||||
$(sysdep-CPPFLAGS)
|
||||
override CFLAGS = $(+cflags) $(sysdep-CFLAGS)
|
||||
$(sysdep-CPPFLAGS) $(CPPFLAGS-$(suffix $@))
|
||||
override CFLAGS = $(+cflags) $(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) \
|
||||
$(CFLAGS-$(<F))
|
||||
|
||||
|
||||
# This is the macro that the implicit linking rules use.
|
||||
@@ -351,6 +430,41 @@ ifneq "$(filter -g,$(+cflags))" "" # -g is in $(+cflags)
|
||||
LDFLAGS := -g
|
||||
endif
|
||||
|
||||
|
||||
# Enable object files for different versions of the library.
|
||||
# Various things use $(object-suffixes) to know what all to make.
|
||||
# The compilation rules use $(CPPFLAGS-${SUFFIX}) and $(CFLAGS-${SUFFIX})
|
||||
# to pass different flags for each flavor.
|
||||
libtypes = $(foreach o,$(object-suffixes),$(libtype$o))
|
||||
object-suffixes := .o
|
||||
libtype.o := lib%.a
|
||||
ifeq (yes,$(build-shared))
|
||||
# Under --enable-shared, we will build a shared library of PIC objects.
|
||||
# The PIC object files are named foo.so.
|
||||
object-suffixes += .so
|
||||
CPPFLAGS-.so = -DPIC
|
||||
CFLAGS-.so = -fPIC
|
||||
libtype.so := lib%_pic.a
|
||||
endif
|
||||
ifeq (yes,$(build-profile))
|
||||
# Under --enable-profile, we will build a static library of profiled objects.
|
||||
# The profiled object files are named foo.po.
|
||||
object-suffixes += .po
|
||||
CFLAGS-.po = -p
|
||||
libtype.po = lib%_p.a
|
||||
endif
|
||||
ifeq (yes,$(build-omitfp))
|
||||
# Under --enable-omitfp, we build an the library optimized without
|
||||
# debugging information using -fomit-frame-pointer, and build an extra
|
||||
# library with debugging information. The debuggable objects are named foo.go.
|
||||
object-suffixes += .go
|
||||
CFLAGS-.go = -g
|
||||
CFLAGS-.o = -g0 -O99 -fomit-frame-pointer
|
||||
CFLAGS-.so += $(CFLAGS.o)
|
||||
libtype.go = lib%_g.a
|
||||
endif
|
||||
|
||||
|
||||
+gnu-stabs = $(shell echo>&2 '*** BARF ON ME')
|
||||
|
||||
ifneq ($(BUILD_CC),$(CC))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -29,9 +29,11 @@ endif
|
||||
all: lib others
|
||||
|
||||
define autoconf-it
|
||||
@-rm -f $@.new
|
||||
autoconf $(ACFLAGS) $< > $@.new
|
||||
chmod a-w,a+x $@.new
|
||||
mv -f $@.new $@
|
||||
test -d CVS && cvs commit -m'Regenerated: autoconf $(ACFLAGS) $<' $@
|
||||
test ! -d CVS || cvs commit -m'Regenerated: autoconf $(ACFLAGS) $<' $@
|
||||
endef
|
||||
|
||||
configure: configure.in; $(autoconf-it)
|
||||
@@ -49,14 +51,14 @@ sysdep-subdirs := $(subst $(\n), ,$(sysdep-subdirs))
|
||||
endif
|
||||
|
||||
# These are the subdirectories containing the library source.
|
||||
subdirs := elf csu assert ctype locale math setjmp signal stdio stdlib \
|
||||
malloc string time dirent grp pwd posix io termios resource \
|
||||
socket misc gnulib $(wildcard crypt) manual \
|
||||
$(sysdep-subdirs)
|
||||
subdirs = csu assert ctype db locale intl math setjmp signal stdlib \
|
||||
stdio-common $(stdio) malloc string time dirent grp pwd \
|
||||
posix io termios resource misc socket sysvipc gmon gnulib \
|
||||
$(wildcard crypt) manual $(sysdep-subdirs) elf
|
||||
export subdirs := $(subdirs) # Benign, useless in GNU make before 3.63.
|
||||
|
||||
# The mach and hurd subdirectories have many generated header files which
|
||||
# the much of rest of the library depends on, so it is best to build them
|
||||
# much of the rest of the library depends on, so it is best to build them
|
||||
# first (and mach before hurd, at that). The before-compile additions in
|
||||
# sysdeps/{mach,hurd}/Makefile should make it reliably work for these files
|
||||
# not to exist when making in other directories, but it will be slower that
|
||||
@@ -79,7 +81,8 @@ subdirs := $(filter mach,$(subdirs)) $(filter hurd,$(subdirs)) \
|
||||
no-libc.a bin lib \
|
||||
data headers others)
|
||||
|
||||
headers := features.h errno.h sys/errno.h errnos.h limits.h
|
||||
headers := errno.h sys/errno.h errnos.h limits.h values.h \
|
||||
features.h gnu-versions.h
|
||||
aux = sysdep $(libc-init) version
|
||||
|
||||
echo-headers: subdir_echo-headers
|
||||
@@ -103,8 +106,13 @@ include Makerules
|
||||
# Install from subdirectories too.
|
||||
install: subdir_install
|
||||
|
||||
lib-noranlib $(libc.a)(__.SYMDEF): subdir_lib
|
||||
# Build subdirectory lib objects.
|
||||
lib-noranlib: subdir_lib
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
# Build the shared object from the PIC object library.
|
||||
lib: $(common-objpfx)libc.so
|
||||
endif
|
||||
|
||||
$(objpfx)sysd-dirs: $(+sysdir_pfx)config.make
|
||||
(echo define sysdep-subdirs; \
|
||||
@@ -166,10 +174,12 @@ $(all-subdirs-targets):
|
||||
|
||||
# Subroutines of all cleaning targets.
|
||||
parent-mostlyclean: common-mostlyclean # common-mostlyclean is in Makerules.
|
||||
-rm -f $(libc.a) $(addprefix $(objpfx),$(install-lib))
|
||||
-rm -f $(foreach o,$(object-suffixes),\
|
||||
$(common-objpfx)$(patsubst %,$(libtype$o),c)) \
|
||||
$(addprefix $(objpfx),$(install-lib))
|
||||
parent-clean: parent-mostlyclean common-clean
|
||||
-rm -f $(addprefix $(common-objpfx),$(common-generated))
|
||||
-rm -f $(addprefix $(+sysdir_pfx),sysd-Makefile sysd-dirs sysd-rules)
|
||||
-rm -f $(addprefix $(objpfx),sysd-Makefile sysd-dirs sysd-rules)
|
||||
|
||||
clean: parent-clean
|
||||
# This is done this way rather than having `subdir_clean' be a
|
||||
@@ -192,8 +202,8 @@ realclean distclean: parent-clean
|
||||
# Subroutine of distclean and realclean.
|
||||
distclean-1: subdir_$(distclean-1)
|
||||
-rm -f $(config-generated)
|
||||
-rm -f $(addprefix $(objpfx),config.status cache.cache)
|
||||
-rm -f $(addprefix $(objpfx),config.make config-name.h)
|
||||
-rm -f $(addprefix $(objpfx),config.status config.cache config.log)
|
||||
-rm -f $(addprefix $(objpfx),config.make config-name.h config.h)
|
||||
ifdef objdir
|
||||
-rm -f $(objpfx)Makefile
|
||||
endif
|
||||
@@ -210,11 +220,13 @@ parent_echo-distinfo:
|
||||
|
||||
# Make the distribution tarfile.
|
||||
|
||||
distribute := README INSTALL NOTES COPYING.LIB COPYING ChangeLog NEWS \
|
||||
distribute := README INSTALL NOTES COPYING.LIB COPYING NEWS \
|
||||
ChangeLog ChangeLog.[0-9] \
|
||||
Makefile Makeconfig Makerules Rules Make-dist MakeTAGS \
|
||||
extra-lib.mk o-iterator.mk \
|
||||
ansidecl.h mkinstalldirs move-if-change install-sh \
|
||||
configure configure.in aclocal.m4 config.sub config.guess\
|
||||
config.make.in config-name.in Makefile.in \
|
||||
config.make.in config-name.in Makefile.in \
|
||||
munch-tmpl.c munch.awk sysdep.h set-hooks.h libc-symbols.h
|
||||
|
||||
distribute := $(strip $(distribute))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -75,20 +75,21 @@ vpath %.h $(subst $(empty) ,:,$(strip $(common-objpfx) \
|
||||
$(addprefix $(sysdep_dir)/,$(sysdirs)) \
|
||||
$(..)))
|
||||
|
||||
ifeq ($(wildcard $(+sysdir_pfx)sysd-Makefile),)
|
||||
# Don't do deps until this exists, because it might change the sources list.
|
||||
no_deps=t
|
||||
endif
|
||||
|
||||
# Some sysdep makefiles use this to distinguish being included here from
|
||||
# being included individually by a subdir makefile (hurd/Makefile needs this).
|
||||
in-Makerules := yes
|
||||
|
||||
ifndef avoid-generated
|
||||
include $(+sysdir_pfx)sysd-Makefile
|
||||
$(+sysdir_pfx)sysd-Makefile: $(+sysdir_pfx)config.make $(..)Makerules
|
||||
-include $(+sysdir_pfx)sysd-Makefile
|
||||
ifneq ($(sysd-Makefile-sysdirs),$(sysdirs))
|
||||
sysd-Makefile-force = FORCE
|
||||
FORCE:
|
||||
endif
|
||||
$(+sysdir_pfx)sysd-Makefile: $(+sysdir_pfx)config.make $(..)Makerules \
|
||||
$(sysd-Makefile-force)
|
||||
-@rm -f $@T
|
||||
(for dir in $(sysdirs); do \
|
||||
(echo 'sysd-Makefile-sysdirs := $(sysdirs)'; \
|
||||
for dir in $(sysdirs); do \
|
||||
file=sysdeps/$$dir/Makefile; \
|
||||
if [ -f $(..)$$file ]; then \
|
||||
echo include "\$$(..)$$file"; \
|
||||
@@ -98,6 +99,12 @@ $(+sysdir_pfx)sysd-Makefile: $(+sysdir_pfx)config.make $(..)Makerules
|
||||
mv -f $@T $@
|
||||
endif
|
||||
|
||||
ifndef sysd-Makefile-done
|
||||
# Don't do deps until this exists, because it might change the sources list.
|
||||
no_deps=t
|
||||
endif
|
||||
|
||||
|
||||
# Reorder before-compile so that mach things come first, and hurd things
|
||||
# second, before all else. The mach and hurd subdirectories have many
|
||||
# generated header files which the much of rest of the library depends on,
|
||||
@@ -140,10 +147,19 @@ $(objpfx)dummy.d:
|
||||
# compiling in the source tree, generated sources go into the current
|
||||
# directory, and those should be chosen before any sources in sysdeps.
|
||||
$(objpfx)%.o: %.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.so: %.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.po: %.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.go: %.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.d: %.S $(before-compile); $(+make-deps)
|
||||
$(objpfx)%.o: %.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.so: %.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.po: %.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.go: %.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.d: %.s $(objpfx)dummy.d; $(make-dummy-dep)
|
||||
$(objpfx)%.o: %.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.so: %.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.po: %.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.go: %.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.d: %.c $(before-compile); $(+make-deps)
|
||||
|
||||
# Omit the objpfx rules when building in the source tree, because
|
||||
@@ -152,10 +168,19 @@ ifdef objpfx
|
||||
# Define first rules to find the source files in $(objpfx).
|
||||
# Generated source files will end up there.
|
||||
$(objpfx)%.o: $(objpfx)%.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.so: $(objpfx)%.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.po: $(objpfx)%.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.go: $(objpfx)%.S $(before-compile); $(compile-command.S)
|
||||
$(objpfx)%.d: $(objpfx)%.S $(before-compile); $(+make-deps)
|
||||
$(objpfx)%.o: $(objpfx)%.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.so: $(objpfx)%.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.po: $(objpfx)%.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.go: $(objpfx)%.s $(before-compile); $(compile-command.s)
|
||||
$(objpfx)%.d: $(objpfx)%.s $(objpfx)dummy.d; $(make-dummy-dep)
|
||||
$(objpfx)%.o: $(objpfx)%.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.so: $(objpfx)%.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.po: $(objpfx)%.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.go: $(objpfx)%.c $(before-compile); $(compile-command.c)
|
||||
$(objpfx)%.d: $(objpfx)%.c $(before-compile); $(+make-deps)
|
||||
endif
|
||||
|
||||
@@ -166,37 +191,57 @@ ifdef inhibit-sysdep-asm
|
||||
define open-check-inhibit-asm
|
||||
case $$sysdir in $(subst $(empty) ,|,$(inhibit-sysdep-asm))) : ;; *)
|
||||
endef
|
||||
close-check-inhibit-asm = ;; esac
|
||||
close-check-inhibit-asm = ;; esac ;
|
||||
endif
|
||||
|
||||
# Don't include sysd-rules until sysd-Makefile is already there and has been
|
||||
# included. It might define inhibit-sysdep-asm, which would affect the
|
||||
# contents of sysd-rules.
|
||||
ifdef sysd-Makefile-done
|
||||
include $(+sysdir_pfx)sysd-rules
|
||||
-include $(+sysdir_pfx)sysd-rules
|
||||
ifneq ($(sysd-rules-sysdirs),$(sysdirs))
|
||||
# The value of $(sysdirs) the sysd-rules was computed for
|
||||
# differs from the one we are using now. So force a rebuild of sysd-rules.
|
||||
sysd-rules-force = FORCE
|
||||
FORCE:
|
||||
endif
|
||||
endif
|
||||
$(+sysdir_pfx)sysd-rules: $(+sysdir_pfx)config.make $(..)Makerules \
|
||||
$(wildcard $(foreach dir,$(sysdirs),\
|
||||
$(sysdep_dir)/$(dir)/Makefile))
|
||||
$(sysdep_dir)/$(dir)/Makefile))\
|
||||
$(sysd-rules-force)
|
||||
-@rm -f $@T
|
||||
(for sysdir in $(sysdirs); do \
|
||||
(echo 'sysd-rules-sysdirs := $(sysdirs)'; \
|
||||
for sysdir in $(sysdirs); do \
|
||||
dir="\$$(sysdep_dir)/$$sysdir"; \
|
||||
for o in $(object-suffixes); do \
|
||||
$(open-check-inhibit-asm) \
|
||||
echo "\$$(objpfx)%$$o: $$dir/%.S \$$(before-compile); \
|
||||
\$$(compile-command.S)"; \
|
||||
echo "\$$(objpfx)%$$o: $$dir/%.s \$$(before-compile); \
|
||||
\$$(compile-command.s)"; \
|
||||
$(close-check-inhibit-asm) \
|
||||
echo "\$$(objpfx)%$$o: $$dir/%.c \$$(before-compile); \
|
||||
\$$(compile-command.c)"; \
|
||||
done; \
|
||||
$(open-check-inhibit-asm) \
|
||||
echo "\$$(objpfx)%.o: $$dir/%.S \$$(before-compile); \
|
||||
\$$(compile-command.S)"; \
|
||||
echo "\$$(objpfx)%.d: $$dir/%.s \$$(objpfx)dummy.d; \
|
||||
\$$(make-dummy-dep)"; \
|
||||
echo "\$$(objpfx)%.d: $$dir/%.S \$$(before-compile); \
|
||||
\$$(+make-deps)"; \
|
||||
echo "\$$(objpfx)%.o: $$dir/%.s \$$(before-compile); \
|
||||
\$$(compile-command.s)"; \
|
||||
echo "\$$(objpfx)%.d: $$dir/%.s \$$(objpfx)dummy.d; \
|
||||
\$$(make-dummy-dep)" $(close-check-inhibit-asm); \
|
||||
echo "\$$(objpfx)%.o: $$dir/%.c \$$(before-compile); \
|
||||
\$$(compile-command.c)"; \
|
||||
$(close-check-inhibit-asm) \
|
||||
echo "\$$(objpfx)%.d: $$dir/%.c \$$(before-compile); \
|
||||
\$$(+make-deps)"; \
|
||||
done) > $@T
|
||||
done; \
|
||||
echo 'sysd-rules-done = t') > $@T
|
||||
mv -f $@T $@
|
||||
|
||||
ifndef sysd-rules-done
|
||||
# Don't do deps until this exists, because it provides rules to make the deps.
|
||||
no_deps=t
|
||||
endif
|
||||
|
||||
|
||||
ifndef compile-command.S
|
||||
compile-command.S = $(compile.S) $(OUTPUT_OPTION)
|
||||
endif
|
||||
@@ -207,29 +252,23 @@ ifndef compile-command.c
|
||||
compile-command.c = $(compile.c) $(OUTPUT_OPTION)
|
||||
endif
|
||||
|
||||
ifneq ($(filter %gcc,$(notdir $(firstword $(CC)))),)
|
||||
# GCC can grok options after the file name, and it looks nicer that way.
|
||||
compile.S = $(CC) $< -c $(CPPFLAGS) -DASSEMBLER $(asm-CPPFLAGS)
|
||||
compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS)
|
||||
else
|
||||
compile.S = $(COMPILE.S) -DASSEMBLER $(asm-CPPFLAGS) $<
|
||||
compile.c = $(COMPILE.c) $<
|
||||
endif
|
||||
compile.S = $(CC) $< -c $(CPPFLAGS) -DASSEMBLER $(asm-CPPFLAGS)
|
||||
COMPILE.S = $(CC) -c $(CPPFLAGS) -DASSEMBLER $(asm-CPPFLAGS)
|
||||
COMPILE.s = $(filter-out -pipe,$(CC)) -c $(ASFLAGS)
|
||||
|
||||
ifndef OUTPUT_OPTION
|
||||
ifdef objpfx
|
||||
# We need this for the output to go in the right place. It will default to
|
||||
# empty if make was configured to work with a cc that can't grok -c and -o
|
||||
# together. You can't compile the C library with such a compiler.
|
||||
OUTPUT_OPTION = -o $@
|
||||
endif
|
||||
endif
|
||||
|
||||
S-CPPFLAGS = $(asm-CPPFLAGS)
|
||||
define +make-deps
|
||||
-@rm -f $@
|
||||
$(+mkdep) $< $(CPPFLAGS) $($(<:$*.%=%)-CPPFLAGS) | \
|
||||
sed -e 's,$*\.o,$(@:.d=.o) $@,' $(sed-remove-objpfx) > $(@:.d=.T)
|
||||
sed -e 's,$*\.o,$(foreach o,$(object-suffixes),$(@:.d=$o)) $@,' \
|
||||
$(sed-remove-objpfx) > $(@:.d=.T)
|
||||
mv -f $(@:.d=.T) $@
|
||||
endef
|
||||
ifneq (,$(objpfx))
|
||||
@@ -247,33 +286,41 @@ sysdep_routines := $(sysdep_routines)
|
||||
# This is the list of all object files, gotten by
|
||||
# replacing every ".c" in `sources' with a ".o".
|
||||
override objects := $(addprefix $(objpfx),$(sources:.c=.o))
|
||||
|
||||
|
||||
# This variable is used in ``include $(o-iterator)'' after defining
|
||||
# $(o-iterator-doit) to produce some desired rule using $o for the object
|
||||
# suffix, and setting $(object-suffixes-left) to $(object-suffixes); a copy
|
||||
# is produced for each object suffix in use.
|
||||
o-iterator = $(patsubst %,$(..)o-iterator.mk,$(object-suffixes))
|
||||
|
||||
# The makefile may define $(extra-libs) with `libfoo libbar'
|
||||
# to build libfoo.a et al from the modules listed in $(libfoo-routines).
|
||||
ifdef extra-libs
|
||||
# extra-lib.mk is included once for each extra lib to define rules
|
||||
# to build it, and to add its objects to the various variables.
|
||||
# During its evaluation, $(lib) is set to the name of the library.
|
||||
extra-libs-left := $(extra-libs)
|
||||
include $(patsubst %,$(..)extra-lib.mk,$(extra-libs))
|
||||
endif
|
||||
|
||||
+depfiles := $(strip $(sources:.c=.d) \
|
||||
$(patsubst %.o,%.d,$(filter %.o,$(extra-objs))) \
|
||||
$(patsubst %.o,%.d,$(filter %.o,$(extra-objs:.so=.o))) \
|
||||
$(addsuffix .d,$(others) $(tests)))
|
||||
+depfiles := $(addprefix $(objpfx),\
|
||||
$(filter-out $(addsuffix .d,$(omit-deps)),\
|
||||
$(+depfiles)))
|
||||
|
||||
$(objpfx)depend-$(subdir): Makefile
|
||||
ifdef +depfiles
|
||||
for file in $(+depfiles:$(objpfx)%=%); do \
|
||||
echo "include \$$(objpfx)$$file"; \
|
||||
done > $@-tmp
|
||||
mv -f $@-tmp $@
|
||||
else
|
||||
cp /dev/null $@
|
||||
endif
|
||||
|
||||
ifneq ($(no_deps),t)
|
||||
# Include the generated dependencies of the sources in this directory.
|
||||
include $(objpfx)depend-$(subdir)
|
||||
-include $(+depfiles)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Maximize efficiency by minimizing the number of rules.
|
||||
.SUFFIXES: # Clear the suffix list.
|
||||
# Add the suffixes we use.
|
||||
.SUFFIXES: .a .o .S .s .c .h .d
|
||||
.SUFFIXES: .a $(object-suffixes) .S .s .c .h .d
|
||||
|
||||
# Generic rule for making directories.
|
||||
%/:
|
||||
@@ -282,11 +329,10 @@ endif
|
||||
|
||||
# Make sure that object files are not removed
|
||||
# when they are intermediates between sources and library members.
|
||||
# This can go away with make v4.
|
||||
.PRECIOUS: %.o
|
||||
.PRECIOUS: $(addprefix $(objpfx)%,$(object-suffixes))
|
||||
|
||||
# Make sure that the parent library archive is never removed.
|
||||
.PRECIOUS: $(libc.a)
|
||||
.PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
|
||||
|
||||
# Use the verbose option of ar and tar when not running silently.
|
||||
ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
|
||||
@@ -300,43 +346,80 @@ ARFLAGS := r$(verbose)
|
||||
# This makes all the object files in the parent library archive.
|
||||
|
||||
.PHONY: lib libobjs lib-noranlib
|
||||
$(libc.a): $(libc.a)(__.SYMDEF)
|
||||
lib: $(libc.a)
|
||||
lib: lib-noranlib $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
|
||||
|
||||
+libobjs := $(patsubst %,$(libc.a)(%),$(notdir $(objects)))
|
||||
libobjs: $(+libobjs)
|
||||
# Pattern rule for libraries: depend on the __.SYMDEF member updated by ranlib.
|
||||
lib%.a: lib%.a(__.SYMDEF) ;
|
||||
|
||||
libobjs: $(foreach o,$(object-suffixes),\
|
||||
$(common-objpfx)$(patsubst %,$(libtype$o),c)(\
|
||||
$(notdir $(objects:.o=$o))))
|
||||
lib-noranlib: libobjs
|
||||
others: $(addprefix $(objpfx),$(install-lib))
|
||||
|
||||
# Define a pattern rule that will match many targets libc.%(foo.o), for
|
||||
# each foo in $(objects) (% will just happen always to match `a'). This is
|
||||
# the only way to define a rule that updates many targets at once with one
|
||||
# sequence of commands.
|
||||
ifdef objects
|
||||
$(patsubst %,$(libc.a:a=)\%(%),$(notdir $(objects))): $(objpfx)stamp-$(subdir);
|
||||
$(objpfx)stamp-$(subdir): $(objects)
|
||||
# $(+libc_lock_open)
|
||||
ifdef objdir
|
||||
cd $(objdir); $(AR) cru$(verbose) libc.a $(patsubst $(objpfx)%,%,$^)
|
||||
else
|
||||
$(AR) cru$(verbose) $(..)libc.a $^
|
||||
endif
|
||||
# $(+libc_lock_close)
|
||||
|
||||
# Define a pattern rule that will match many targets libc.a(foo.%), for
|
||||
# each foo.o in $(objects) (% will just happen always to match `o'). This is
|
||||
# the only way to define a rule that updates many targets at once with one
|
||||
# sequence of commands. We in fact define the pattern rule to match
|
||||
# targets libc.a(foo.%), libc_pic.a(foo.%), etc, to avoid repeating the rule.
|
||||
# Each match will only ever be called upon to make member objects of
|
||||
# the appropriate type in each library (i.e. libc_pic.a(foo.so)).
|
||||
$(foreach l,$(libtypes),\
|
||||
$(common-objpfx)$(patsubst %,$l,c)($(notdir $(objects:.o=.%)))): \
|
||||
$(objpfx)stamp.%-$(subdir) ;
|
||||
|
||||
# The pattern rule tells Make to remake $(objpfx)stamp.%-$(subdir) as
|
||||
# the way to update all the foo.% object files in $(objects).
|
||||
# Now we define a static pattern rule to update each
|
||||
# $(objpfx)stamp.SUFFIX-$(subdir) timestamp file;
|
||||
# these rules (one explicit rule is generated for each object suffix)
|
||||
# will update the parent archive with
|
||||
$(foreach o,$(object-suffixes),$(objpfx)stamp$o-$(subdir)): \
|
||||
$(objpfx)stamp%-$(subdir): $(objects:.o=%)
|
||||
$(patsubst %,cd %;,$(objdir)) \
|
||||
$(AR) cru$(verbose) ${O%-lib} \
|
||||
$(patsubst $(objpfx)%,%,$^)
|
||||
# `touch' won't let me touch a world-writable file I don't own. Sigh.
|
||||
rm -f $@
|
||||
touch $@
|
||||
ifdef subdir
|
||||
O%-lib = $(filter ../,$(firstword $(objdir) ../))$(patsubst %,$(libtype$*),c)
|
||||
else
|
||||
O%-lib = $(patsubst %,$(libtype$*),c)
|
||||
endif
|
||||
|
||||
$(libc.a)(__.SYMDEF): $(+libobjs)
|
||||
$(RANLIB) $@
|
||||
endif
|
||||
|
||||
define +libc_lock_open
|
||||
@. $(..)libc-lock-open
|
||||
endef
|
||||
define +libc_lock_close
|
||||
@rm -f $(..)LOCK-libc.a
|
||||
endef
|
||||
# Rules to update the __.SYMDEF member with ranlib.
|
||||
# To consolidate, each flavor library's __.SYMDEF member
|
||||
# depends on the imaginary intermediate file `symdef.SUFFIX',
|
||||
# where SUFFIX is that flavor's object suffix; then a pattern rule
|
||||
# "remakes" symdef.% depending on all the libc.a(foo.%) files in $(objects).
|
||||
$(common-objpfx)$(patsubst %,$(libtype.o),c)(__.SYMDEF): symdef.o
|
||||
$(common-objpfx)$(patsubst %,$(libtype.so),c)(__.SYMDEF): symdef.so
|
||||
$(common-objpfx)$(patsubst %,$(libtype.po),c)(__.SYMDEF): symdef.po
|
||||
$(common-objpfx)$(patsubst %,$(libtype.go),c)(__.SYMDEF): symdef.go
|
||||
symdef.%: $(foreach o,$(object-suffixes),\
|
||||
$(common-objpfx)$(patsubst %,$(libtype$o),c)(\
|
||||
$(patsubst $(objpfx)%.o,%.%,$(objects)))) \
|
||||
$(filter subdir_lib,$(firstword $(subdir) subdir_lib))
|
||||
# The last line above makes it also depend on subdir_lib for the parent.
|
||||
$(RANLIB) $(common-objpfx)$(patsubst %,$(libtype.$*),c)
|
||||
|
||||
# This makes all the object files.
|
||||
.PHONY: objects objs
|
||||
objects objs: $(objects) $(addprefix $(objpfx),$(extra-objs))
|
||||
objects objs: $(foreach o,$(object-suffixes),$(objects:.o=$o)) \
|
||||
$(addprefix $(objpfx),$(extra-objs))
|
||||
|
||||
# Canned sequence for building an extra library archive.
|
||||
define build-extra-lib
|
||||
$(patsubst %,cd %;,$(objdir)) \
|
||||
$(AR) cru$(verbose) $(@:$(objpfx)%=%) \
|
||||
$(patsubst $(objpfx)%,%,$^)
|
||||
$(RANLIB) $@
|
||||
endef
|
||||
|
||||
# Installation.
|
||||
|
||||
@@ -373,28 +456,58 @@ endef
|
||||
# should install libc.a; this way "make install" in a subdir is guaranteed
|
||||
# to install everything it changes.
|
||||
ifdef objects
|
||||
install: $(libdir)/lib$(libprefix)$(libc-name).a
|
||||
# We avoid depending on lib-noranlib because that makes the parent make
|
||||
# subdir_lib in all the subdirs, when the make install run they do will
|
||||
# update the library anyway. Running ranlib after installing makes the
|
||||
# __.SYMDEF time stamp up to date, which avoids messages from some linkers.
|
||||
# Depending on subdir_install gets all the subdirs to update the library,
|
||||
# and is optimal for `make install' at top level.
|
||||
$(libdir)/lib$(libprefix)$(libc-name).a: libobjs subdir_install
|
||||
installed-libcs := $(foreach o,$(object-suffixes),\
|
||||
$(libdir)/$(patsubst %,$(libtype$o),\
|
||||
$(libprefix)$(libc-name)))
|
||||
installed-libcs := $(filter-out %_pic.a,$(installed-libcs))
|
||||
install: $(installed-libcs)
|
||||
$(installed-libcs): $(libdir)/lib$(libprefix)%: lib
|
||||
$(make-target-directory)
|
||||
$(INSTALL_DATA) $(libc.a) $@
|
||||
$(INSTALL_DATA) $(common-objpfx)lib$(*:$(libc-name)%=c%) $@
|
||||
# Running ranlib after installing makes the __.SYMDEF time stamp up to
|
||||
# date, which avoids messages from some linkers.
|
||||
$(RANLIB) $@
|
||||
endif
|
||||
|
||||
define do-install-program
|
||||
$(make-target-directory)
|
||||
$(INSTALL_PROGRAM) $< $@.new
|
||||
mv -f $@.new $@
|
||||
endef
|
||||
|
||||
install-lib.so := $(filter %.so,$(install-lib:%_pic.a=%.so))
|
||||
install-lib := $(filter-out %.so %_pic.a,$(install-lib))
|
||||
ifeq (yes,$(build-shared))
|
||||
install-lib-nosubdir: $(foreach so,$(install-lib.so),\
|
||||
$(libdir)/$(patsubst $(libprefix)lib%,lib$(libprefix)%,\
|
||||
$(libprefix)$(so))$($(so)-version))
|
||||
|
||||
install: $(slibdir)/libc.so$(libc.so-version)
|
||||
$(slibdir)/lib$(libprefix)c.so$(libc.so-version): $(common-objpfx)libc.so
|
||||
$(do-install-so)
|
||||
|
||||
define do-install-so
|
||||
$(do-install-program)
|
||||
$(patsubst %,ln -s -f $(@F) $(@D)/$(patsubst %$*.so,%,$(<F))$(libprefix)$*.so,\
|
||||
$(filter-out %.so,$@))
|
||||
endef
|
||||
|
||||
so-versions := $(sort $(foreach so,$(install-lib.so),.so$($(so)-version)))
|
||||
$(foreach v,$(so-versions),\
|
||||
$(libdir)/lib$(libprefix)%$v): $(common-objpfx)lib%.so
|
||||
$(do-install-so)
|
||||
$(foreach v,$(so-versions),\
|
||||
$(libdir)/$(libprefix)%$v): $(common-objpfx)%.so
|
||||
$(do-install-so)
|
||||
endif
|
||||
|
||||
ifdef install-bin
|
||||
$(addprefix $(bindir)/,$(install-bin)): $(bindir)/%: $(objpfx)%
|
||||
$(make-target-directory)
|
||||
$(INSTALL_PROGRAM) $< $@
|
||||
$(do-install-program)
|
||||
endif
|
||||
ifdef install-sbin
|
||||
$(addprefix $(sbindir)/,$(install-sbin)): $(sbindir)/%: $(objpfx)%
|
||||
$(make-target-directory)
|
||||
$(INSTALL_PROGRAM) $< $@
|
||||
$(do-install-program)
|
||||
endif
|
||||
ifdef install-lib
|
||||
install-lib.a := $(filter lib%.a,$(install-lib))
|
||||
@@ -443,6 +556,43 @@ install-no-libc.a-nosubdir: install-headers-nosubdir install-data-nosubdir\
|
||||
install-others-nosubdir install-sbin-nosubdir
|
||||
install: install-no-libc.a-nosubdir
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
# Pattern rule to build a shared object from an archive of PIC objects.
|
||||
# This must come after the installation rules so Make doesn't try to
|
||||
# build shared libraries in place from the installed *_pic.a files.
|
||||
# $(LDLIBS-%.so) may contain -l switches to generate run-time dependencies
|
||||
# on other shared objects.
|
||||
lib%.so: lib%_pic.a; $(build-shlib)
|
||||
|
||||
define build-shlib
|
||||
$(LINK.o) -shared -o $@ $(sysdep-LDFLAGS) $(config-LDFLAGS) \
|
||||
-Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
|
||||
$(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
|
||||
-Wl,-rpath-link=$(common-objdir) -Wl,-rpath=$(libdir) \
|
||||
-Wl,--whole-archive $^ $(LDLIBS-$(@F:lib%.so=%).so)
|
||||
endef
|
||||
|
||||
# Don't try to use -lc when making libc.so itself.
|
||||
# Also omits crti.o and crtn.o, which we do not want
|
||||
# since we define our own `.init' section specially.
|
||||
LDFLAGS-c.so = -nostdlib -nostartfiles
|
||||
# Give libc.so an entry point and make it directly runnable itself.
|
||||
LDFLAGS-c.so += -e __libc_print_version
|
||||
# Use our own special initializer and finalizer files for libc.so.
|
||||
elfobjdir := $(firstword $(objdir) $(..)elf)
|
||||
$(common-objpfx)libc.so: $(elfobjdir)/soinit.so \
|
||||
$(common-objpfx)libc_pic.a \
|
||||
$(elfobjdir)/sofini.so
|
||||
$(build-shlib)
|
||||
|
||||
ifdef libc.so-version
|
||||
$(common-objpfx)libc.so$(libc.so-version): $(common-objpfx)libc.so
|
||||
rm -f $@
|
||||
ln -s $(<F) $@ || ln $< $@
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Command to compile $< in $(objdir) using the native libraries.
|
||||
define native-compile
|
||||
cwd=`pwd`; cd $(@D); $(BUILD_CC) $(BUILD_CFLAGS) \
|
||||
@@ -481,13 +631,17 @@ common-mostlyclean:
|
||||
-rm -f $(addprefix $(objpfx),$(tests) $(others) \
|
||||
$(addsuffix .o,$(tests) $(others)) \
|
||||
$(addsuffix .out,$(tests)))
|
||||
-rm -f $(objects) $(addprefix $(objpfx),$(extra-objs) stamp-$(subdir))
|
||||
-rm -f core TAGS
|
||||
-rm -f $(addprefix $(objpfx),$(extra-objs) $(install-lib))
|
||||
-rm -f core $(objpfx)stub-$(subdir)
|
||||
$(rmobjs)
|
||||
define rmobjs
|
||||
$(foreach o,$(object-suffixes),
|
||||
-rm -f $(addprefix $(objpfx),stamp$o-$(subdir)) $(objects:.o=$o))
|
||||
endef
|
||||
|
||||
# Also remove the dependencies and generated source files.
|
||||
common-clean: common-mostlyclean
|
||||
-rm -f $(objpfx)depend-$(subdir) $(+depfiles)
|
||||
-rm -f $(addprefix $(objpfx),$(generated))
|
||||
-rm -f $(addprefix $(objpfx),$(generated)) $(+depfiles)
|
||||
|
||||
# Produce a file `stub-$(subdir)' which contains `#define __stub_FUNCTION'
|
||||
# for each function which is a stub. We grovel over all the .d files
|
||||
@@ -510,10 +664,12 @@ $(common-objpfx)stub-$(subdir): $(+depfiles)
|
||||
# Make the distribution tar file.
|
||||
|
||||
.PHONY: dist
|
||||
dist: distinfo $(..)Make-dist
|
||||
dist: distinfo $(..)Make-dist
|
||||
$(MAKE) -f $< -f $(word 2,$^) $(Make-dist-args)
|
||||
|
||||
dist: $(distribute)
|
||||
# Avoid depending on source files found in sysdeps dirs,
|
||||
# because the references affect implicit rule selection.
|
||||
dist: $(filter-out %.c %.S %.s,$(distribute))
|
||||
|
||||
# We used to simply export all these variables, but that frequently made the
|
||||
# environment get too large. Instead, we write all the information into
|
||||
@@ -539,6 +695,6 @@ $(gpl2lgpl): %: $(..)gpl2lgpl.sed /home/gd/gnu/lib/%
|
||||
# So I don't edit them by mistake.
|
||||
chmod a-w $@-tmp
|
||||
mv -f $@-tmp $@
|
||||
test -d CVS && cvs commit -m'Updated from $^' $@
|
||||
test ! -d CVS || cvs commit -m'Updated from $^' $@
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
GNU C Library NEWS -- history of user-visible changes. 24 February 1995
|
||||
GNU C Library NEWS -- history of user-visible changes. 2 January 1996
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
|
||||
See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports to bug-glibc@prep.ai.mit.edu.
|
||||
@@ -16,6 +16,59 @@ Version 1.10
|
||||
of many files which contained only symbol aliases, reducing the size of
|
||||
the source and the compiled library; many other files were renamed to
|
||||
less cryptic names previously occupied by the symbol alias files.
|
||||
There is a new header file <elf.h> and new library `-lelf' for
|
||||
programs which operate on files in the ELF format.
|
||||
|
||||
* Converted to Autoconf version 2, so `configure' has more options.
|
||||
Run `configure --help' to see the details.
|
||||
|
||||
* The library can now be configured to build profiling, highly-optimized
|
||||
(but undebuggable), and/or shared libraries (ELF with GNU ld only). The
|
||||
`--enable-profile', `--enable-omitfp', and `--enable-shared' options to
|
||||
`configure' enable building these extra libraries. The shared library is
|
||||
built by default when using both ELF and GNU ld. When shared libraries
|
||||
are enabled, the new library `-ldl' is available for arbitrary run-time
|
||||
loading of shared objects; its interface is defined in <dlfcn.h>. The
|
||||
new header file <link.h> gives access to the internals of the run-time
|
||||
dynamic linker, `ld.so'.
|
||||
|
||||
* The C library now provides the run-time support code for profiling
|
||||
executables compiled with `-pg'. Programs can control the profiling code
|
||||
through the interface in <sys/gmon.h>. The profiling code was adapted
|
||||
from 4.4 BSD-Lite.
|
||||
|
||||
* The new functions `strtoq' and `strtouq' parse integer values from
|
||||
strings, like `strtol' and `strtoul', but they return `long long int' and
|
||||
`unsigned long long int' values, respectively (64-bit quantities).
|
||||
|
||||
* The new functions `strtof' and `strtold' parse floating-point values from
|
||||
strings, like `strtod', but they return `float' and `long double' values,
|
||||
respectively (on some machines `double' and `long double' are the same).
|
||||
|
||||
* Ulrich Drepper has contributed new implementations of the floating-point
|
||||
printing and reading code used in the `printf' family of functions and
|
||||
`strtod', `strtof', and `strtold'. These new functions are perfectly
|
||||
accurate, and much faster than the old ones.
|
||||
|
||||
* The new header <langinfo.h> defines an interface for accessing
|
||||
various locale-dependent data (using the locale chosen with `setlocale').
|
||||
|
||||
* You can now use positional parameter specifications in format strings
|
||||
for the `printf' and `scanf' families of functions. For example,
|
||||
`printf ("Number %2$d, Mr %1$s\n", "Jones", 6);'' prints
|
||||
``Number 6, Mr Jones''. This is mainly useful when providing different
|
||||
format strings for different languages, whose grammars may dictate
|
||||
different orderings of the values being printed. To support this
|
||||
feature, the interface for `register_printf_handler' has changed; see
|
||||
the header file <printf.h> for details.
|
||||
|
||||
* The `printf' and `scanf' families of functions now understand a new
|
||||
formatting flag for numeric conversions: the ' flag (e.g. %'d or %'f) says
|
||||
to group numbers as indicated by the locale; for `scanf' and friends, this
|
||||
says to accept as valid only a number with all the proper grouping
|
||||
separators in the right places. In the default "C" locale, numbers are
|
||||
not grouped; but locales for specific countries will define the usual
|
||||
conventions (i.e. separate thousands with `,' in the US locale).
|
||||
|
||||
* The pgrp functions have been regularized, slightly incompatibly but much
|
||||
less confusingly. The core functions are now `getpgid' and `setpgid',
|
||||
@@ -27,23 +80,12 @@ Version 1.10
|
||||
* The new header file <fts.h> and suite of functions simplify programs that
|
||||
operate on directory trees. This code comes from 4.4 BSD.
|
||||
|
||||
* Converted to Autoconf version 2, so `configure' has more options.
|
||||
Run `configure --help' to see the details.
|
||||
|
||||
* The resolver code has been updated from the BIND-4.9.3-BETA14 release.
|
||||
* The resolver code has been updated from the BIND 4.9.3 release.
|
||||
|
||||
* The new function `malloc_find_object_address' finds the starting address
|
||||
of a malloc'd block, given any address within the block. This can be
|
||||
useful for debugging.
|
||||
|
||||
* The new functions `strtoq' and `strtouq' parse integer values from
|
||||
strings, like `strtol' and `strtoul', but they return `long long int' and
|
||||
`unsigned long long int' values, respectively (64-bit quantities).
|
||||
|
||||
* The new functions `strtof' and `strtold' parse floating-point values from
|
||||
strings, like `strtod', but they return `float' and `long double' values,
|
||||
respectively (on some machines `double' and `long double' are the same).
|
||||
|
||||
* There is a new malloc debugging hook `__memalign_hook'.
|
||||
|
||||
* There are new typedefs `ushort' for `unsigned short int' and `uint' for
|
||||
@@ -53,19 +95,78 @@ Version 1.10
|
||||
* The `-lmcheck' library to enable standard malloc debugging hooks is now
|
||||
done differently, so that it works even without GNU ld.
|
||||
|
||||
* Ulrich Drepper has contributed new implementations of the floating-point
|
||||
printing and reading code used in the `printf' family of functions and
|
||||
`strtod', `strtof', and `strtold'. These new functions are perfectly
|
||||
accurate, and much faster than the old ones.
|
||||
|
||||
* The `printf' family of functions now understand a new formatting flag
|
||||
for numeric conversions: the ' flag (e.g. %'d or %'f) says to group
|
||||
numbers as indicated by the locale. In the default "C" locale, numbers
|
||||
are not grouped; but locales for specific countries will define the
|
||||
usual conventions (i.e. separate thousands with `,' in the US locale).
|
||||
|
||||
* New function `euidaccess' checks allowed access to a file like `access',
|
||||
but using the effective IDs instead of the real IDs.
|
||||
|
||||
* The time zone data files have been updated for the latest and greatest
|
||||
local time conventions of the countries of the world.
|
||||
|
||||
* The new function `dirfd' extracts the file descriptor used by a DIR stream;
|
||||
see <dirent.h>.
|
||||
|
||||
* The new functions `ecvt', `fcvt', and `gcvt' provide an obsolete interface
|
||||
for formatting floating-point numbers. They are provided only for
|
||||
compatibility; new programs should use `sprintf' instead.
|
||||
|
||||
* The new auxiliary library `-lutil' from 4.4 BSD contains various
|
||||
functions for maintaining the login-record files (primarily of use to
|
||||
system programs such as `login'), and convenient functions for
|
||||
allocating and initializing a pseudo-terminal (pty) device.
|
||||
|
||||
* Ulrich Drepper has contributed new support for System V style
|
||||
shared memory and IPC on systems that support it.
|
||||
|
||||
* Ulrich Drepper has contributed several miscellaneous new functions found
|
||||
in System V: The `hsearch' family of functions provide an effective
|
||||
implementation of hash tables; `a64l' and `l64a' provide a very simple
|
||||
binary to ASCII mapping; `drand48' and friends provide a 48-bit random
|
||||
number generator.
|
||||
|
||||
* Ulrich Drepper has contributed new reentrant counterparts for the
|
||||
`random' and `hsearch' families of functions; `random_r', `hsearch_r', etc.
|
||||
|
||||
* Ulrich Drepper has contributed new, highly-optimized versions of several
|
||||
string functions for the i486/Pentium family of processors.
|
||||
|
||||
* Ulrich Drepper has updated the Linux-specific code, based largely
|
||||
on work done in Hongjiu Lu's version of GNU libc for Linux.
|
||||
The GNU library now supports Linux versions 1.3.29 and later,
|
||||
using the ELF object file format (i[345]86-*-linux).
|
||||
|
||||
* Ulrich Drepper has contributed a new set of message catalog functions to
|
||||
support multiple languages, for use with his new package GNU gettext.
|
||||
|
||||
* New header file <values.h> gives SVID-compatible names for <limits.h>
|
||||
constants.
|
||||
|
||||
* Various new macros, declarations, and small header files for compatibility
|
||||
with 4.4 BSD.
|
||||
|
||||
* New function `group_member' is a convenient way to check if a process has
|
||||
a given effective group ID.
|
||||
|
||||
* When using GCC 2.7 and later, the socket functions are now declared in a
|
||||
special way so that passing an argument of type `struct sockaddr_in *',
|
||||
`struct sockaddr_ns *', or `struct sockaddr_un *' instead of the generic
|
||||
`struct sockaddr *' type, does not generate a type-clash warning.
|
||||
|
||||
* New function `error' declared in header file <error.h> is a convenient
|
||||
function for printing error messages and optionally exitting; this is the
|
||||
canonical function used in GNU programs. The new functions `err', `warn',
|
||||
and friends in header file <err.h> are the canonical 4.4 BSD interface for
|
||||
doing the same thing.
|
||||
|
||||
* The <glob.h> interface has several new flags from 4.4 BSD that extend the
|
||||
POSIX.2 `glob' function to do ~ and {...} expansion.
|
||||
|
||||
* New function `unsetenv' complements `setenv' for compatibility with 4.4 BSD.
|
||||
|
||||
* New function `getsid' returns session ID number on systems that support it.
|
||||
|
||||
* The 4.4 BSD `db' library has been incorporated into the GNU C library.
|
||||
New header files <db.h> and <mpool.h> provide a rich set of functions for
|
||||
several types of simple databases stored in memory and in files, and
|
||||
<ndbm.h> is an old `ndbm'-compatbile interface using the `db' functions.
|
||||
|
||||
Version 1.09
|
||||
|
||||
@@ -298,7 +399,7 @@ Version 1.04
|
||||
compiler, so the C library should now work with C++ code.
|
||||
|
||||
* The header file <bstring.h> is gone. <string.h> now declares bcopy,
|
||||
bcmp, bzero, and ffs.
|
||||
bcmp, bzero, and ffs.
|
||||
|
||||
* Mike Haertel (of GNU e?grep and malloc fame) has written a new sorting
|
||||
function which uses the `merge sort' algorithm, and is said to be
|
||||
@@ -324,7 +425,7 @@ Version 1.04
|
||||
----------------------------------------------------------------------
|
||||
Copyright information:
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to anyone to make or distribute verbatim copies
|
||||
of this document as received, in any medium, provided that the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
This directory contains the version 1.09.5 test release of the GNU C Library.
|
||||
This directory contains the version 1.09.6 test release of the GNU C Library.
|
||||
Many bugs have been fixed since the last release.
|
||||
Some bugs surely remain.
|
||||
|
||||
@@ -37,7 +37,7 @@ provides the Unix `crypt' function, plus some other entry points.
|
||||
Because of the United States export restriction on DES implementations,
|
||||
we are distributing this code separately from the rest of the C
|
||||
library. There is an extra distribution tar file just for crypt; it is
|
||||
called `glibc-1.09.5-crypt.tar.gz'. You can just unpack the crypt
|
||||
called `glibc-1.09.6-crypt.tar.gz'. You can just unpack the crypt
|
||||
distribution along with the rest of the C library and build; you can
|
||||
also build the library without getting crypt. Users outside the USA
|
||||
can get the crypt distribution via anonymous FTP from ftp.uni-c.dk
|
||||
|
||||
@@ -55,7 +55,7 @@ endif
|
||||
include ../Makerules
|
||||
|
||||
.PHONY: subdir_lib
|
||||
subdir_lib: objs lib-noranlib
|
||||
subdir_lib: lib-noranlib
|
||||
|
||||
# Some subdirs need to install a dummy library.
|
||||
# They can use "$(objpfx)libfnord.a: $(dep-dummy-lib); $(make-dummy-lib)".
|
||||
@@ -67,11 +67,12 @@ $(objpfx)dummy.o:
|
||||
@rm -f $(@:.o=.c)
|
||||
echo 'void __dummy__ () { }' > $(@:.o=.c)
|
||||
$(CC) -c $(@:.o=.c) -o $@
|
||||
generated := $(generated) dummy.o dummy.c
|
||||
|
||||
# This makes all the auxilliary and test programs.
|
||||
|
||||
.PHONY: others tests
|
||||
others: $(addprefix $(objpfx),$(others))
|
||||
others: $(addprefix $(objpfx),$(others) $(extra-objs))
|
||||
ifeq ($(cross-compiling),yes)
|
||||
tests: $(addprefix $(objpfx),$(tests))
|
||||
else
|
||||
@@ -79,21 +80,22 @@ tests: $(tests:%=$(objpfx)%.out)
|
||||
endif
|
||||
|
||||
ifneq "$(strip $(others) $(tests))" ""
|
||||
$(addprefix $(objpfx),$(others) $(tests)): %: %.o $(libc.a)
|
||||
$(addprefix $(objpfx),$(others) $(tests)): %: %.o \
|
||||
$(sort $(filter $(common-objpfx)libc%,$(link-libc)))
|
||||
$(+link)
|
||||
endif
|
||||
|
||||
ifneq "$(strip $(tests))" ""
|
||||
# These are the implicit rules for making test outputs
|
||||
# from the test programs and whatever input files are present.
|
||||
$(objpfx)%.out: $(objpfx)% %.args %.input
|
||||
$(dir $<)$(notdir $<) `cat $(word 2,$^)` < $(word 3,$^) > $@
|
||||
$(objpfx)%.out: $(objpfx)% %.args
|
||||
$(dir $<)$(notdir $<) `cat $(word 2,$^)` > $@
|
||||
$(objpfx)%.out: $(objpfx)% %.input
|
||||
$(dir $<)$(notdir $<) < $(word 2,$^) > $@
|
||||
$(objpfx)%.out: $(objpfx)%
|
||||
$(dir $<)$(notdir $<) > $@
|
||||
$(objpfx)%.out: %.args $(objpfx)% %.input
|
||||
$(built-program-cmd) `cat $(word 1,$^)` < $(word 3,$^) > $@
|
||||
$(objpfx)%.out: %.args $(objpfx)%
|
||||
$(built-program-cmd) `cat $(word 1,$^)` > $@
|
||||
$(objpfx)%.out: %.input $(objpfx)%
|
||||
$(built-program-cmd) < $(word 1,$^) > $@
|
||||
$(objpfx)%.out: /dev/null $(objpfx)% # Make it 2nd arg for canned sequence.
|
||||
$(built-program-cmd) > $@
|
||||
endif # tests
|
||||
|
||||
.PHONY: distclean realclean subdir_distclean subdir_realclean \
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
@@ -43,7 +43,7 @@ __assert_perror_fail (int errnum,
|
||||
#endif
|
||||
|
||||
/* Print the message. */
|
||||
(void) fprintf (stderr, "%s%s%s:%u: %s%sUnexpected error: %s.\n",
|
||||
(void) fprintf (stderr, _("%s%s%s:%u: %s%sUnexpected error: %s.\n"),
|
||||
__assert_program_name ? __assert_program_name : "",
|
||||
__assert_program_name ? ": " : "",
|
||||
file, line,
|
||||
|
||||
+2
-2
@@ -38,14 +38,14 @@ CONST char *__assert_program_name;
|
||||
void
|
||||
DEFUN(__assert_fail, (assertion, file, line, function),
|
||||
CONST char *assertion AND
|
||||
CONST char *file AND unsigned int line AND CONST char *function)
|
||||
CONST char *file AND unsigned int line AND CONST char *function)
|
||||
{
|
||||
#ifdef FATAL_PREPARE
|
||||
FATAL_PREPARE;
|
||||
#endif
|
||||
|
||||
/* Print the message. */
|
||||
(void) fprintf (stderr, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
|
||||
(void) fprintf (stderr, _("%s%s%s:%u: %s%sAssertion `%s' failed.\n"),
|
||||
__assert_program_name ? __assert_program_name : "",
|
||||
__assert_program_name ? ": " : "",
|
||||
file, line,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
@@ -18,3 +18,9 @@
|
||||
#ifdef sun. */
|
||||
|
||||
#undef sun
|
||||
|
||||
/* The source code copied from BIND for inet_addr/inet_aton
|
||||
doesn't actually define the functions without these macros. */
|
||||
|
||||
#define NEED_INETADDR 1
|
||||
#define NEED_INETATON 1
|
||||
|
||||
Vendored
+98
-20
@@ -14,7 +14,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
@@ -59,6 +59,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
echo alpha-dec-osf${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
21064:Windows_NT:50:3)
|
||||
echo alpha-dec-winnt3.5
|
||||
exit 0 ;;
|
||||
amiga:NetBSD:*:*)
|
||||
echo m68k-cbm-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
@@ -75,6 +78,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
sun4*:SunOS:5.*:*)
|
||||
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
i86pc:SunOS:5.*:*)
|
||||
echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit 0 ;;
|
||||
sun4*:SunOS:6*:*)
|
||||
# According to config.sub, this is the proper way to canonicalize
|
||||
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
|
||||
@@ -93,15 +99,30 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
sun3*:SunOS:*:*)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
atari*:NetBSD:*:*)
|
||||
echo m68k-atari-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
sun3*:NetBSD:*:*)
|
||||
echo m68k-sun-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mac68k:NetBSD:*:*)
|
||||
echo m68k-apple-netbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RISC*:ULTRIX:*:*)
|
||||
echo mips-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
VAX*:ULTRIX*:*:*)
|
||||
echo vax-dec-ultrix${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mips:*:4*:UMIPS)
|
||||
echo mips-mips-riscos4sysv
|
||||
exit 0 ;;
|
||||
mips:*:5*:RISCos)
|
||||
echo mips-mips-riscos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
Night_Hawk:Power_UNIX:*:*)
|
||||
echo powerpc-harris-powerunix
|
||||
exit 0 ;;
|
||||
m88k:CX/UX:7*:*)
|
||||
echo m88k-harris-cxux7
|
||||
exit 0 ;;
|
||||
@@ -112,12 +133,17 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
echo m88k-motorola-sysv3
|
||||
exit 0 ;;
|
||||
AViiON:dgux:*:*)
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`uname -p`
|
||||
if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88100 ] ; then
|
||||
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
|
||||
-o ${TARGET_BINARY_INTERFACE}x = x ] ; then
|
||||
echo m88k-dg-dgux${UNAME_RELEASE}
|
||||
else
|
||||
echo m88k-dg-dguxbcs${UNAME_RELEASE}
|
||||
fi
|
||||
else echo i586-dg-dgux${UNAME_RELEASE}
|
||||
fi
|
||||
exit 0 ;;
|
||||
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
|
||||
echo m88k-dolphin-sysv3
|
||||
@@ -169,10 +195,8 @@ EOF
|
||||
else
|
||||
IBM_ARCH=powerpc
|
||||
fi
|
||||
if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
IBM_REV=4.1
|
||||
elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
|
||||
IBM_REV=4.1.1
|
||||
if [ -x /usr/bin/oslevel ] ; then
|
||||
IBM_REV=`/usr/bin/oslevel`
|
||||
else
|
||||
IBM_REV=4.${UNAME_RELEASE}
|
||||
fi
|
||||
@@ -203,7 +227,7 @@ EOF
|
||||
case "${UNAME_MACHINE}" in
|
||||
9000/31? ) HP_ARCH=m68000 ;;
|
||||
9000/[34]?? ) HP_ARCH=m68k ;;
|
||||
9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
|
||||
9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;;
|
||||
9000/8?? ) HP_ARCH=hppa1.0 ;;
|
||||
esac
|
||||
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
|
||||
@@ -239,18 +263,21 @@ EOF
|
||||
rm -f dummy.c dummy
|
||||
echo unknown-hitachi-hiuxwe2
|
||||
exit 0 ;;
|
||||
9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
|
||||
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
|
||||
echo hppa1.1-hp-bsd
|
||||
exit 0 ;;
|
||||
9000/8??:4.3bsd:*:*)
|
||||
echo hppa1.0-hp-bsd
|
||||
exit 0 ;;
|
||||
hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
|
||||
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
|
||||
echo hppa1.1-hp-osf
|
||||
exit 0 ;;
|
||||
hp8??:OSF1:*:*)
|
||||
echo hppa1.0-hp-osf
|
||||
exit 0 ;;
|
||||
parisc*:Lites*:*:*)
|
||||
echo hppa1.1-hp-lites
|
||||
exit 0 ;;
|
||||
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
|
||||
echo c1-convex-bsd
|
||||
exit 0 ;;
|
||||
@@ -269,13 +296,16 @@ EOF
|
||||
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
|
||||
echo c4-convex-bsd
|
||||
exit 0 ;;
|
||||
CRAY*X-MP:UNICOS:*:*)
|
||||
CRAY*X-MP:*:*:*)
|
||||
echo xmp-cray-unicos
|
||||
exit 0 ;;
|
||||
CRAY*Y-MP:UNICOS:*:*)
|
||||
echo ymp-cray-unicos
|
||||
exit 0 ;;
|
||||
CRAY-2:UNICOS:*:*)
|
||||
CRAY*Y-MP:*:*:*)
|
||||
echo ymp-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY*C90:*:*:*)
|
||||
echo c90-cray-unicos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
CRAY-2:*:*:*)
|
||||
echo cray2-cray-unicos
|
||||
exit 0 ;;
|
||||
hp3[0-9][05]:NetBSD:*:*)
|
||||
@@ -294,8 +324,39 @@ EOF
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
exit 0 ;;
|
||||
*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux
|
||||
exit 0 ;;
|
||||
# The BFD linker knows what the default object file format is, so
|
||||
# first see if it will tell us.
|
||||
ld_help_string=`ld --help 2>&1`
|
||||
if echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
|
||||
echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
|
||||
elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
|
||||
echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
|
||||
elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
|
||||
echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
|
||||
elif test "${UNAME_MACHINE}" = "alpha" ; then
|
||||
echo alpha-unknown-linux ; exit 0
|
||||
else
|
||||
# Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
|
||||
# useful --help. Gcc wants to distinguish between linuxoldld and linuxaout.
|
||||
test ! -d /usr/lib/ldscripts/. \
|
||||
&& echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
|
||||
# Determine whether the default compiler is a.out or elf
|
||||
cat >dummy.c <<EOF
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
#ifdef __ELF__
|
||||
printf ("%s-unknown-linux\n", argv[1]);
|
||||
#else
|
||||
printf ("%s-unknown-linuxaout\n", argv[1]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
|
||||
rm -f dummy.c dummy
|
||||
fi ;;
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
|
||||
# are messed up and put the nodename in both sysname and nodename.
|
||||
i[34]86:DYNIX/ptx:4*:*)
|
||||
@@ -315,6 +376,8 @@ EOF
|
||||
elif /bin/uname -X 2>/dev/null >/dev/null ; then
|
||||
UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
|
||||
(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
|
||||
(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
|
||||
&& UNAME_MACHINE=i586
|
||||
echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-sysv32
|
||||
@@ -345,19 +408,19 @@ EOF
|
||||
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
|
||||
uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& echo i486-ncr-sysv4 && exit 0 ;;
|
||||
m680[234]0:LynxOS:2.2*:*)
|
||||
m680[234]0:LynxOS:2.[23]*:*)
|
||||
echo m68k-lynx-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
mc68030:UNIX_System_V:4.*:*)
|
||||
echo m68k-atari-sysv4
|
||||
exit 0 ;;
|
||||
i[34]86:LynxOS:2.2*:*)
|
||||
i[34]86:LynxOS:2.[23]*:*)
|
||||
echo i386-lynx-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
TSUNAMI:LynxOS:2.2*:*)
|
||||
TSUNAMI:LynxOS:2.[23]*:*)
|
||||
echo sparc-lynx-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
rs6000:LynxOS:2.2*:*)
|
||||
rs6000:LynxOS:2.[23]*:*)
|
||||
echo rs6000-lynx-lynxos${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
RM*:SINIX-*:*:*)
|
||||
@@ -377,6 +440,10 @@ esac
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
cat >dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
# include <sys/types.h>
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
@@ -440,7 +507,18 @@ main ()
|
||||
#endif
|
||||
|
||||
#if defined (_SEQUENT_)
|
||||
printf ("i386-sequent-ptx\n"); exit (0);
|
||||
struct utsname un;
|
||||
|
||||
uname(&un);
|
||||
|
||||
if (strncmp(un.version, "V2", 2) == 0) {
|
||||
printf ("i386-sequent-ptx2\n"); exit (0);
|
||||
}
|
||||
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
|
||||
printf ("i386-sequent-ptx1\n"); exit (0);
|
||||
}
|
||||
printf ("i386-sequent-ptx\n"); exit (0);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (vax)
|
||||
|
||||
+14
@@ -11,15 +11,29 @@
|
||||
linker being used. Set by --with-weak-symbols. */
|
||||
#undef HAVE_WEAK_SYMBOLS
|
||||
|
||||
/* Define if not using ELF, but `.init' and `.fini' sections are available. */
|
||||
#undef HAVE_INITFINI
|
||||
|
||||
/* Define if using the GNU assembler, gas. */
|
||||
#undef HAVE_GNU_AS
|
||||
|
||||
/* Define if the assembler supports the `.set' directive. */
|
||||
#undef HAVE_ASM_SET_DIRECTIVE
|
||||
|
||||
/* Define to the name of the assembler's directive for
|
||||
declaring a symbol global (default `.globl'). */
|
||||
#undef ASM_GLOBAL_DIRECTIVE
|
||||
|
||||
/* ELF has weak symbols, and with GNU ld a.out does too. */
|
||||
#ifndef HAVE_WEAK_SYMBOLS
|
||||
#if defined (HAVE_ELF) || defined (HAVE_GNU_LD)
|
||||
#define HAVE_WEAK_SYMBOLS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define to use GNU libio instead of GNU stdio.
|
||||
This is defined by configure under --enable-libio. */
|
||||
#undef USE_IN_LIBIO
|
||||
/* */
|
||||
/* These symbols might be defined by some sysdeps configures. */
|
||||
|
||||
|
||||
+18
-4
@@ -2,23 +2,37 @@
|
||||
# From $Id$.
|
||||
# Don't edit this file. Put configuration parameters in configparms instead.
|
||||
|
||||
# Installation prefixes.
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
# System configuration.
|
||||
config-machine = @host_cpu@
|
||||
config-vendor = @host_vendor@
|
||||
config-os = @host_os@
|
||||
config-sysdirs = @sysnames@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
config-defines = @DEFS@
|
||||
gnu-as = @gnu_as@
|
||||
gnu-ld = @gnu_ld@
|
||||
|
||||
elf = @elf@
|
||||
weak-symbols = @weak@
|
||||
have-initfini = @libc_cv_have_initfini@
|
||||
|
||||
# Configuration options.
|
||||
gnu-as = @gnu_as@
|
||||
gnu-ld = @gnu_ld@
|
||||
build-shared = @shared@
|
||||
build-profile = @profile@
|
||||
build-omitfp = @omitfp@
|
||||
stdio = @stdio@
|
||||
|
||||
# Build tools.
|
||||
CC = @CC@
|
||||
AR = @AR@
|
||||
RANLIB = @RANLIB@
|
||||
AS = $(CC) -c
|
||||
|
||||
# Installation tools.
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
Vendored
+80
-19
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Configuration validation subroutine script, version 1.1.
|
||||
# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
# can handle that machine. It does not imply ALL GNU software can.
|
||||
@@ -17,7 +17,8 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
@@ -87,6 +88,10 @@ case $os in
|
||||
-hiux*)
|
||||
os=-hiuxwe2
|
||||
;;
|
||||
-sco5)
|
||||
os=sco3.2v5
|
||||
basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
|
||||
;;
|
||||
-sco4)
|
||||
os=-sco3.2v4
|
||||
basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
|
||||
@@ -128,10 +133,11 @@ esac
|
||||
case $basic_machine in
|
||||
# Recognize the basic CPU types without company name.
|
||||
# Some are omitted here because they have special meanings below.
|
||||
tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
|
||||
tahoe | i[3456]86 | i860 | m68k | m68000 | m88k | ns32k | arm \
|
||||
| arme[lb] | pyramid \
|
||||
| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
|
||||
| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
|
||||
| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
|
||||
| powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
|
||||
| pdp11 | mips64el | mips64orion | mips64orionel \
|
||||
| sparc)
|
||||
basic_machine=$basic_machine-unknown
|
||||
@@ -142,13 +148,13 @@ case $basic_machine in
|
||||
exit 1
|
||||
;;
|
||||
# Recognize the basic CPU types with company name.
|
||||
vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
|
||||
vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
|
||||
| sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
|
||||
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
|
||||
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
|
||||
| none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
|
||||
| hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
|
||||
| pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
|
||||
| pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
|
||||
| pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
|
||||
| mips64el-* | mips64orion-* | mips64orionel-*)
|
||||
;;
|
||||
# Recognize the various machine names and aliases which stand
|
||||
@@ -306,19 +312,19 @@ case $basic_machine in
|
||||
os=-mvs
|
||||
;;
|
||||
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
||||
i[345]86v32)
|
||||
i[3456]86v32)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
|
||||
os=-sysv32
|
||||
;;
|
||||
i[345]86v4*)
|
||||
i[3456]86v4*)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
|
||||
os=-sysv4
|
||||
;;
|
||||
i[345]86v)
|
||||
i[3456]86v)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
|
||||
os=-sysv
|
||||
;;
|
||||
i[345]86sol2)
|
||||
i[3456]86sol2)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
|
||||
os=-solaris2
|
||||
;;
|
||||
@@ -417,17 +423,47 @@ case $basic_machine in
|
||||
pc532 | pc532-*)
|
||||
basic_machine=ns32k-pc532
|
||||
;;
|
||||
pentium-*)
|
||||
# We will change tis to say i586 once there has been
|
||||
# time for various packages to start to recognize that.
|
||||
basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
pentium | p5)
|
||||
basic_machine=i586-intel
|
||||
;;
|
||||
pentiumpro | p6)
|
||||
basic_machine=i686-intel
|
||||
;;
|
||||
pentium-* | p5-*)
|
||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumpro-* | p6-*)
|
||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
k5)
|
||||
# We don't have specific support for AMD's K5 yet, so just call it a Pentium
|
||||
basic_machine=i586-amd
|
||||
;;
|
||||
nexen)
|
||||
# We don't have specific support for Nexgen yet, so just call it a Pentium
|
||||
basic_machine=i586-nexgen
|
||||
;;
|
||||
pn)
|
||||
basic_machine=pn-gould
|
||||
;;
|
||||
power) basic_machine=rs6000-ibm
|
||||
;;
|
||||
ppc) basic_machine=powerpc-unknown
|
||||
;;
|
||||
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||
basic_machine=powerpcle-unknown
|
||||
;;
|
||||
ppcle-* | powerpclittle-*)
|
||||
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ps2)
|
||||
basic_machine=i386-ibm
|
||||
;;
|
||||
rm[46]00)
|
||||
basic_machine=mips-siemens
|
||||
;;
|
||||
rtpc | rtpc-*)
|
||||
basic_machine=romp-ibm
|
||||
;;
|
||||
@@ -516,6 +552,10 @@ case $basic_machine in
|
||||
basic_machine=m68k-wrs
|
||||
os=-vxworks
|
||||
;;
|
||||
vxworks29k)
|
||||
basic_machine=a29k-wrs
|
||||
os=-vxworks
|
||||
;;
|
||||
xmp)
|
||||
basic_machine=xmp-cray
|
||||
os=-unicos
|
||||
@@ -598,17 +638,19 @@ case $os in
|
||||
;;
|
||||
# First accept the basic system types.
|
||||
# The portable systems comes first.
|
||||
# Each alternative must end in a *, to match a version number.
|
||||
# Each alternative MUST END IN A *, to match a version number.
|
||||
# -sysv* is not here because it comes later, after sysvr4.
|
||||
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
|
||||
| -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
|
||||
| -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[3456]* \
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
|
||||
| -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
|
||||
| -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \
|
||||
| -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
|
||||
| -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
|
||||
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta | -udi | -eabi)
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-sunos5*)
|
||||
os=`echo $os | sed -e 's|sunos5|solaris2|'`
|
||||
@@ -634,6 +676,16 @@ case $os in
|
||||
-ctix* | -uts*)
|
||||
os=-sysv
|
||||
;;
|
||||
-ns2 )
|
||||
os=-nextstep2
|
||||
;;
|
||||
# Preserve the version number of sinix5.
|
||||
-sinix5.*)
|
||||
os=`echo $os | sed -e 's|sinix|sysv|'`
|
||||
;;
|
||||
-sinix*)
|
||||
os=-sysv4
|
||||
;;
|
||||
-triton*)
|
||||
os=-sysv3
|
||||
;;
|
||||
@@ -680,6 +732,9 @@ case $basic_machine in
|
||||
*-acorn)
|
||||
os=-riscix1.2
|
||||
;;
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
pdp11-*)
|
||||
os=-none
|
||||
;;
|
||||
@@ -731,6 +786,9 @@ case $basic_machine in
|
||||
m88k-omron*)
|
||||
os=-luna
|
||||
;;
|
||||
*-next )
|
||||
os=-nextstep
|
||||
;;
|
||||
*-sequent)
|
||||
os=-ptx
|
||||
;;
|
||||
@@ -758,6 +816,9 @@ case $basic_machine in
|
||||
*-sgi)
|
||||
os=-irix
|
||||
;;
|
||||
*-siemens)
|
||||
os=-sysv4
|
||||
;;
|
||||
*-masscomp)
|
||||
os=-rtu
|
||||
;;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#! /bin/sh
|
||||
|
||||
# From configure.in Id: configure.in,v 1.72 1995/01/30 07:26:57 roland Exp roland
|
||||
# From configure.in CVSid
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated automatically using autoconf version 2.1.1
|
||||
# Generated automatically using autoconf version 2.7
|
||||
# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
#
|
||||
# This configure script is free software; the Free Software Foundation
|
||||
@@ -14,6 +14,10 @@ ac_default_prefix=/usr/local
|
||||
# Any additions from configure.in:
|
||||
ac_help="$ac_help
|
||||
--with-gmp=DIRECTORY find GMP source code in DIRECTORY (not needed)"
|
||||
ac_help="$ac_help
|
||||
--with-gettext=DIR find GNU gettext source code in DIR (not needed)"
|
||||
ac_help="$ac_help
|
||||
--with-fp if using floating-point hardware"
|
||||
ac_help="$ac_help
|
||||
--with-gnu-binutils if using GNU binutils (as and ld)"
|
||||
ac_help="$ac_help
|
||||
@@ -24,6 +28,14 @@ ac_help="$ac_help
|
||||
--with-elf if using the ELF object format"
|
||||
ac_help="$ac_help
|
||||
--with-weak-symbols if weak symbols are available in as and ld"
|
||||
ac_help="$ac_help
|
||||
--enable-libio build in GNU libio instead of GNU stdio"
|
||||
ac_help="$ac_help
|
||||
--enable-shared build shared library [default=yes if GNU ld & ELF]"
|
||||
ac_help="$ac_help
|
||||
--enable-profile build profiled library [default=yes]"
|
||||
ac_help="$ac_help
|
||||
--enable-omitfp build undebuggable optimized library [default=no]"
|
||||
|
||||
# Initialize some variables set by options.
|
||||
# The variables have the same names as the options, with
|
||||
@@ -46,9 +58,22 @@ target=NONE
|
||||
verbose=
|
||||
x_includes=NONE
|
||||
x_libraries=NONE
|
||||
bindir='${exec_prefix}/bin'
|
||||
sbindir='${exec_prefix}/sbin'
|
||||
libexecdir='${exec_prefix}/libexec'
|
||||
datadir='${prefix}/share'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
libdir='${exec_prefix}/lib'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
infodir='${prefix}/info'
|
||||
mandir='${prefix}/man'
|
||||
|
||||
# Initialize some other variables.
|
||||
subdirs=
|
||||
MFLAGS= MAKEFLAGS=
|
||||
|
||||
ac_prev=
|
||||
for ac_option
|
||||
@@ -70,9 +95,14 @@ do
|
||||
|
||||
case "$ac_option" in
|
||||
|
||||
-build | --build | --buil | --bui | --bu | --b)
|
||||
-bindir | --bindir | --bindi | --bind | --bin | --bi)
|
||||
ac_prev=bindir ;;
|
||||
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
|
||||
bindir="$ac_optarg" ;;
|
||||
|
||||
-build | --build | --buil | --bui | --bu)
|
||||
ac_prev=build ;;
|
||||
-build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
|
||||
-build=* | --build=* | --buil=* | --bui=* | --bu=*)
|
||||
build="$ac_optarg" ;;
|
||||
|
||||
-cache-file | --cache-file | --cache-fil | --cache-fi \
|
||||
@@ -82,6 +112,12 @@ do
|
||||
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
|
||||
cache_file="$ac_optarg" ;;
|
||||
|
||||
-datadir | --datadir | --datadi | --datad | --data | --dat | --da)
|
||||
ac_prev=datadir ;;
|
||||
-datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
|
||||
| --da=*)
|
||||
datadir="$ac_optarg" ;;
|
||||
|
||||
-disable-* | --disable-*)
|
||||
ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
|
||||
# Reject names that are not valid shell variable names.
|
||||
@@ -132,12 +168,29 @@ Configuration:
|
||||
Directory and file names:
|
||||
--prefix=PREFIX install architecture-independent files in PREFIX
|
||||
[$ac_default_prefix]
|
||||
--exec-prefix=PREFIX install architecture-dependent files in PREFIX
|
||||
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
|
||||
[same as prefix]
|
||||
--bindir=DIR user executables in DIR [EPREFIX/bin]
|
||||
--sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
|
||||
--libexecdir=DIR program executables in DIR [EPREFIX/libexec]
|
||||
--datadir=DIR read-only architecture-independent data in DIR
|
||||
[PREFIX/share]
|
||||
--sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data in DIR
|
||||
[PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
|
||||
--libdir=DIR object code libraries in DIR [EPREFIX/lib]
|
||||
--includedir=DIR C header files in DIR [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
|
||||
--infodir=DIR info documentation in DIR [PREFIX/info]
|
||||
--mandir=DIR man documentation in DIR [PREFIX/man]
|
||||
--srcdir=DIR find the sources in DIR [configure dir or ..]
|
||||
--program-prefix=PREFIX prepend PREFIX to installed program names
|
||||
--program-suffix=SUFFIX append SUFFIX to installed program names
|
||||
--program-transform-name=PROGRAM run sed PROGRAM on installed program names
|
||||
--program-transform-name=PROGRAM
|
||||
run sed PROGRAM on installed program names
|
||||
EOF
|
||||
cat << EOF
|
||||
Host type:
|
||||
--build=BUILD configure for building on BUILD [BUILD=HOST]
|
||||
--host=HOST configure for HOST [guessed]
|
||||
@@ -149,8 +202,10 @@ Features and packages:
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--x-includes=DIR X include files are in DIR
|
||||
--x-libraries=DIR X library files are in DIR
|
||||
--enable and --with options recognized:$ac_help
|
||||
EOF
|
||||
if test -n "$ac_help"; then
|
||||
echo "--enable and --with options recognized:$ac_help"
|
||||
fi
|
||||
exit 0 ;;
|
||||
|
||||
-host | --host | --hos | --ho)
|
||||
@@ -158,6 +213,44 @@ EOF
|
||||
-host=* | --host=* | --hos=* | --ho=*)
|
||||
host="$ac_optarg" ;;
|
||||
|
||||
-includedir | --includedir | --includedi | --included | --include \
|
||||
| --includ | --inclu | --incl | --inc)
|
||||
ac_prev=includedir ;;
|
||||
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
|
||||
| --includ=* | --inclu=* | --incl=* | --inc=*)
|
||||
includedir="$ac_optarg" ;;
|
||||
|
||||
-infodir | --infodir | --infodi | --infod | --info | --inf)
|
||||
ac_prev=infodir ;;
|
||||
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
|
||||
infodir="$ac_optarg" ;;
|
||||
|
||||
-libdir | --libdir | --libdi | --libd)
|
||||
ac_prev=libdir ;;
|
||||
-libdir=* | --libdir=* | --libdi=* | --libd=*)
|
||||
libdir="$ac_optarg" ;;
|
||||
|
||||
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
|
||||
| --libexe | --libex | --libe)
|
||||
ac_prev=libexecdir ;;
|
||||
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
|
||||
| --libexe=* | --libex=* | --libe=*)
|
||||
libexecdir="$ac_optarg" ;;
|
||||
|
||||
-localstatedir | --localstatedir | --localstatedi | --localstated \
|
||||
| --localstate | --localstat | --localsta | --localst \
|
||||
| --locals | --local | --loca | --loc | --lo)
|
||||
ac_prev=localstatedir ;;
|
||||
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
|
||||
| --localstate=* | --localstat=* | --localsta=* | --localst=* \
|
||||
| --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
|
||||
localstatedir="$ac_optarg" ;;
|
||||
|
||||
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
|
||||
ac_prev=mandir ;;
|
||||
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
|
||||
mandir="$ac_optarg" ;;
|
||||
|
||||
-nfp | --nfp | --nf)
|
||||
# Obsolete; use --without-fp.
|
||||
with_fp=no ;;
|
||||
@@ -170,6 +263,15 @@ EOF
|
||||
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
|
||||
no_recursion=yes ;;
|
||||
|
||||
-oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
|
||||
| --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
|
||||
| --oldin | --oldi | --old | --ol | --o)
|
||||
ac_prev=oldincludedir ;;
|
||||
-oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
|
||||
| --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
|
||||
| --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
|
||||
oldincludedir="$ac_optarg" ;;
|
||||
|
||||
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
|
||||
ac_prev=prefix ;;
|
||||
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
|
||||
@@ -210,6 +312,23 @@ EOF
|
||||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
| --sbi=* | --sb=*)
|
||||
sbindir="$ac_optarg" ;;
|
||||
|
||||
-sharedstatedir | --sharedstatedir | --sharedstatedi \
|
||||
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
|
||||
| --sharedst | --shareds | --shared | --share | --shar \
|
||||
| --sha | --sh)
|
||||
ac_prev=sharedstatedir ;;
|
||||
-sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
|
||||
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
|
||||
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
|
||||
| --sha=* | --sh=*)
|
||||
sharedstatedir="$ac_optarg" ;;
|
||||
|
||||
-site | --site | --sit)
|
||||
ac_prev=site ;;
|
||||
-site=* | --site=* | --sit=*)
|
||||
@@ -220,6 +339,13 @@ EOF
|
||||
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
|
||||
srcdir="$ac_optarg" ;;
|
||||
|
||||
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
|
||||
| --syscon | --sysco | --sysc | --sys | --sy)
|
||||
ac_prev=sysconfdir ;;
|
||||
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
|
||||
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
|
||||
sysconfdir="$ac_optarg" ;;
|
||||
|
||||
-target | --target | --targe | --targ | --tar | --ta | --t)
|
||||
ac_prev=target ;;
|
||||
-target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
|
||||
@@ -229,7 +355,7 @@ EOF
|
||||
verbose=yes ;;
|
||||
|
||||
-version | --version | --versio | --versi | --vers)
|
||||
echo "configure generated by autoconf version 2.1.1"
|
||||
echo "configure generated by autoconf version 2.7"
|
||||
exit 0 ;;
|
||||
|
||||
-with-* | --with-*)
|
||||
@@ -275,7 +401,7 @@ EOF
|
||||
-*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
|
||||
;;
|
||||
|
||||
*)
|
||||
*)
|
||||
if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
|
||||
echo "configure: warning: $ac_option: invalid host type" 1>&2
|
||||
fi
|
||||
@@ -394,9 +520,12 @@ fi
|
||||
|
||||
ac_ext=c
|
||||
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='${CC-cc} conftest.$ac_ext $CFLAGS $CPPFLAGS -c 1>&5 2>&5'
|
||||
ac_link='${CC-cc} conftest.$ac_ext $CFLAGS $CPPFLAGS $LDFLAGS -o conftest $LIBS 1>&5 2>&5'
|
||||
ac_cpp='echo $CPP $CPPFLAGS 1>&5;
|
||||
$CPP $CPPFLAGS'
|
||||
ac_compile='echo ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5;
|
||||
${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5'
|
||||
ac_link='echo ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5;
|
||||
${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5'
|
||||
|
||||
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
|
||||
# Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
|
||||
@@ -426,8 +555,8 @@ config_vars=
|
||||
|
||||
# Check for a --with-gmp argument and set gmp-srcdir in config.make.
|
||||
# Check whether --with-gmp or --without-gmp was given.
|
||||
withval="$with_gmp"
|
||||
if test -n "$withval"; then
|
||||
if test "${with_gmp+set}" = set; then
|
||||
withval="$with_gmp"
|
||||
case "$with_gmp" in
|
||||
yes) { echo "configure: error: --with-gmp requires an argument; use --with-gmp=DIRECTORY" 1>&2; exit 1; } ;;
|
||||
''|no) ;;
|
||||
@@ -437,49 +566,110 @@ esac
|
||||
|
||||
fi
|
||||
|
||||
# Check for a --with-gettext argument and set gettext-srcdir in config.make.
|
||||
# Check whether --with-gettext or --without-gettext was given.
|
||||
if test "${with_gettext+set}" = set; then
|
||||
withval="$with_gettext"
|
||||
case "$with_gettext" in
|
||||
yes)
|
||||
{ echo "configure: error: --with-gettext requires an argument; use --with-gettext=DIR" 1>&2; exit 1; } ;;
|
||||
''|no) ;;
|
||||
*)
|
||||
config_vars="$config_vars
|
||||
gettext-srcdir = $withval" ;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-fp or --without-fp was given.
|
||||
if test "${with_fp+set}" = set; then
|
||||
withval="$with_fp"
|
||||
with_fp=$withval
|
||||
else
|
||||
with_fp=yes
|
||||
fi
|
||||
|
||||
# Check whether --with-gnu-binutils or --without-gnu-binutils was given.
|
||||
withval="$with_gnu_binutils"
|
||||
if test -n "$withval"; then
|
||||
gnu_binutils=yes
|
||||
if test "${with_gnu_binutils+set}" = set; then
|
||||
withval="$with_gnu_binutils"
|
||||
gnu_binutils=$withval
|
||||
else
|
||||
gnu_binutils=no
|
||||
fi
|
||||
|
||||
# Check whether --with-gnu-ld or --without-gnu-ld was given.
|
||||
withval="$with_gnu_ld"
|
||||
if test -n "$withval"; then
|
||||
gnu_ld=yes
|
||||
if test "${with_gnu_ld+set}" = set; then
|
||||
withval="$with_gnu_ld"
|
||||
gnu_ld=$withval
|
||||
else
|
||||
gnu_ld=no
|
||||
fi
|
||||
|
||||
# Check whether --with-gnu-as or --without-gnu-as was given.
|
||||
withval="$with_gnu_as"
|
||||
if test -n "$withval"; then
|
||||
gnu_as=yes
|
||||
if test "${with_gnu_as+set}" = set; then
|
||||
withval="$with_gnu_as"
|
||||
gnu_as=$withval
|
||||
else
|
||||
gnu_as=no
|
||||
fi
|
||||
|
||||
test $gnu_binutils = yes && gnu_as=yes gnu_ld=yes
|
||||
# Check whether --with-elf or --without-elf was given.
|
||||
withval="$with_elf"
|
||||
if test -n "$withval"; then
|
||||
elf=yes
|
||||
if test "${with_elf+set}" = set; then
|
||||
withval="$with_elf"
|
||||
elf=$withval
|
||||
else
|
||||
elf=no
|
||||
fi
|
||||
|
||||
# Check whether --with-weak-symbols or --without-weak-symbols was given.
|
||||
withval="$with_weak_symbols"
|
||||
if test -n "$withval"; then
|
||||
weak=yes
|
||||
if test "${with_weak_symbols+set}" = set; then
|
||||
withval="$with_weak_symbols"
|
||||
weak=$withval
|
||||
else
|
||||
weak=no
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-libio or --disable-libio was given.
|
||||
if test "${enable_libio+set}" = set; then
|
||||
enableval="$enable_libio"
|
||||
if test $enableval = yes; then
|
||||
stdio=libio
|
||||
else
|
||||
stdio=stdio
|
||||
fi
|
||||
else
|
||||
stdio=default
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-shared or --disable-shared was given.
|
||||
if test "${enable_shared+set}" = set; then
|
||||
enableval="$enable_shared"
|
||||
shared=$enableval
|
||||
else
|
||||
shared=default
|
||||
fi
|
||||
|
||||
# Check whether --enable-profile or --disable-profile was given.
|
||||
if test "${enable_profile+set}" = set; then
|
||||
enableval="$enable_profile"
|
||||
profile=$enableval
|
||||
else
|
||||
profile=yes
|
||||
fi
|
||||
|
||||
# Check whether --enable-omitfp or --disable-omitfp was given.
|
||||
if test "${enable_omitfp+set}" = set; then
|
||||
enableval="$enable_omitfp"
|
||||
omitfp=$enableval
|
||||
else
|
||||
omitfp=no
|
||||
fi
|
||||
|
||||
|
||||
ac_aux_dir=
|
||||
for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
|
||||
if test -f $ac_dir/install-sh; then
|
||||
@@ -530,9 +720,22 @@ echo "$ac_t""$host" 1>&4
|
||||
# $machine, $vendor, and $os, and changes them whenever convenient.
|
||||
config_machine=$host_cpu config_vendor=$host_vendor config_os=$host_os
|
||||
|
||||
# Some configurations imply other options.
|
||||
case "$host_os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
# These systems always use GNU tools.
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$host_os" in
|
||||
gnu* | linux* | sysv4* | solaris2*)
|
||||
# These systems always use the ELF format.
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
# Compute the list of sysdep directories for this configuration.
|
||||
sysdep_dir=$srcdir/sysdeps
|
||||
echo $ac_n "checking sysdep dirs""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_sysdirs'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'libc_cv_sysdirs'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
machine=$config_machine
|
||||
@@ -542,22 +745,18 @@ os=$config_os
|
||||
# Expand the configuration machine name into a subdirectory by architecture
|
||||
# type and particular chip.
|
||||
case "$machine" in
|
||||
i[345]86)
|
||||
machine=i386/$machine ;;
|
||||
sparc[6789])
|
||||
machine=sparc/$machine ;;
|
||||
m68k)
|
||||
machine=m68k/m68020 ;;
|
||||
m680?0)
|
||||
machine=m68k/$machine ;;
|
||||
m88k)
|
||||
machine=m88k/m88100 ;;
|
||||
m88???)
|
||||
machine=m88k/$machine ;;
|
||||
mips64*)
|
||||
machine=mips/mips64/$machine ;;
|
||||
mips*)
|
||||
machine=mips/$machine ;;
|
||||
a29k | am29000) machine=a29k ;;
|
||||
alpha*) machine=alpha/$machine ;;
|
||||
hppa*) machine=hppa/$machine ;;
|
||||
i[345]86) machine=i386/$machine ;;
|
||||
m680?0) machine=m68k/$machine ;;
|
||||
m68k) machine=m68k/m68020 ;;
|
||||
m88???) machine=m88k/$machine ;;
|
||||
m88k) machine=m88k/m88100 ;;
|
||||
mips*) machine=mips/$machine ;;
|
||||
mips64*) machine=mips/mips64/$machine ;;
|
||||
sparc[6789]) machine=sparc/$machine ;;
|
||||
supersparc) machine=sparc/sparc8 ;;
|
||||
esac
|
||||
|
||||
# Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1.
|
||||
@@ -566,11 +765,11 @@ os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`"
|
||||
case "$os" in
|
||||
gnu*)
|
||||
base_os=mach/hurd ;;
|
||||
netbsd* | 386bsd*)
|
||||
netbsd* | 386bsd* | freebsd* | bsdi*)
|
||||
base_os=unix/bsd/bsd4.4 ;;
|
||||
osf1* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
|
||||
osf* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
|
||||
base_os=unix/bsd ;;
|
||||
linux* | sysv* | isc* | esix* | sco* | minix* | irix4*)
|
||||
sysv* | isc* | esix* | sco* | minix* | irix4* | linux*)
|
||||
base_os=unix/sysv ;;
|
||||
solaris[2-9]*)
|
||||
base_os=unix/sysv/sysv4 ;;
|
||||
@@ -586,7 +785,7 @@ ostry=$os
|
||||
while o=`echo $tail | sed 's/\.[^.]*$//'`; test $o != $tail; do
|
||||
ostry="$ostry /$o"
|
||||
tail=$o
|
||||
done
|
||||
done
|
||||
o=`echo $tail | sed 's/[0-9]*$//'`
|
||||
if test $o != $tail; then
|
||||
ostry="$ostry /$o"
|
||||
@@ -606,6 +805,10 @@ mach=
|
||||
tail=$machine
|
||||
while m=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$m"; do
|
||||
set $m
|
||||
# Prepend the machine's FPU directory unless --without-fp.
|
||||
if test "$with_fp" = yes; then
|
||||
mach="$mach /$1/fpu"
|
||||
fi
|
||||
mach="$mach /$1"
|
||||
tail="$2"
|
||||
done
|
||||
@@ -619,6 +822,7 @@ for b in $base ''; do
|
||||
for o in /$ostry ''; do
|
||||
for m in $mach ''; do
|
||||
try="$m0$b$v$o$m"
|
||||
test -n "$enable_debug_configure" && echo "$0 DEBUG: try $try" >&2
|
||||
if test -d $sysdep_dir$try; then
|
||||
sysnames="$sysnames $try"
|
||||
{ test -n "$o" || test -n "$b"; } && os_used=t
|
||||
@@ -639,19 +843,26 @@ fi
|
||||
|
||||
# We have now validated the configuration.
|
||||
|
||||
|
||||
# If using ELF, look for an `elf' subdirectory of each machine directory.
|
||||
# We prepend these rather than inserting them whereever the machine appears
|
||||
# because things specified by the machine's ELF ABI should override
|
||||
# OS-specific things, and should always be the same for any OS on the
|
||||
# machine (otherwise what's the point of an ABI?).
|
||||
if test "$elf" = yes; then
|
||||
elf_dirs=
|
||||
for m in $mach; do
|
||||
if test -d $sysdep_dir$m/elf; then
|
||||
elf_dirs="$elf_dirs $m/elf"
|
||||
fi
|
||||
done
|
||||
sysnames="`echo $elf_dirs | sed -e 's,^/,,' -e 's, /,,g'` $sysnames"
|
||||
fi
|
||||
|
||||
|
||||
# Remove the leading slashes.
|
||||
sysnames="`echo $sysnames | sed -e 's@^/@@' -e 's@ /@ @g'`"
|
||||
|
||||
# Prepend the machine's FPU directory unless --without-fp.
|
||||
if test "$with_fp" = no; then
|
||||
fpu_dirs=
|
||||
for m in $mach; do
|
||||
if test -d $sysdep_dir$m/fpu; then
|
||||
fpu_dirs="$fpu_dirs $m/fpu"
|
||||
fi
|
||||
done
|
||||
sysnames="`echo $fpu_dirs | sed -e 's,^/,,' -e 's, /,,g'` $sysnames"
|
||||
fi
|
||||
|
||||
# Expand the list of system names into a full list of directories
|
||||
# from each element's parent name and Implies file (if present).
|
||||
@@ -711,17 +922,8 @@ done
|
||||
libc_cv_sysdirs="$sysnames"
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_sysdirs" 1>&4
|
||||
sysnames="$libc_cv_sysdirs"
|
||||
echo "$ac_t""${sysnames}" 1>&4
|
||||
|
||||
case "$host_os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$host_os" in
|
||||
gnu*elf* | linux*elf* | sysv4* | solaris2*)
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
# Find a good install program. We prefer a C program (faster),
|
||||
# so one script is as good as another. But avoid the broken or
|
||||
@@ -735,7 +937,7 @@ esac
|
||||
# ./install, which can be erroneously created by make from ./install.sh.
|
||||
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&4
|
||||
if test -z "$INSTALL"; then
|
||||
if eval "test \"`echo '${'ac_cv_path_install'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
|
||||
@@ -762,10 +964,17 @@ else
|
||||
esac
|
||||
done
|
||||
IFS="$ac_save_ifs"
|
||||
# As a last resort, use the slow shell script.
|
||||
test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh"
|
||||
|
||||
fi
|
||||
INSTALL="$ac_cv_path_install"
|
||||
if test "${ac_cv_path_install+set}" = set; then
|
||||
INSTALL="$ac_cv_path_install"
|
||||
else
|
||||
# As a last resort, use the slow shell script. We don't cache a
|
||||
# path for INSTALL within a source directory, because that will
|
||||
# break other packages using the cache if that directory is
|
||||
# removed, or if the path is relative.
|
||||
INSTALL="$ac_install_sh"
|
||||
fi
|
||||
fi
|
||||
echo "$ac_t""$INSTALL" 1>&4
|
||||
|
||||
@@ -806,7 +1015,7 @@ fi
|
||||
# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}gcc; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
if test -n "$CC"; then
|
||||
@@ -836,7 +1045,7 @@ fi
|
||||
# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}ar; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'ac_cv_prog_AR'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
if test -n "$AR"; then
|
||||
@@ -866,7 +1075,7 @@ fi
|
||||
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
if test -n "$RANLIB"; then
|
||||
@@ -896,7 +1105,7 @@ if test -n "$ac_tool_prefix"; then
|
||||
# Extract the first word of "ranlib", so it can be a program name with args.
|
||||
set dummy ranlib; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
if test -n "$RANLIB"; then
|
||||
@@ -932,7 +1141,7 @@ if test -n "$CPP" && test -d "$CPP"; then
|
||||
CPP=
|
||||
fi
|
||||
if test -z "$CPP"; then
|
||||
if eval "test \"`echo '${'ac_cv_prog_CPP'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
# This must be in double quotes, not single quotes, because CPP may get
|
||||
@@ -941,7 +1150,7 @@ else
|
||||
# On the NeXT, cc -E runs the code through the compiler's parser,
|
||||
# not just through cpp.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 945 "configure"
|
||||
#line 1154 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
@@ -955,7 +1164,7 @@ else
|
||||
rm -rf conftest*
|
||||
CPP="${CC-cc} -E -traditional-cpp"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 959 "configure"
|
||||
#line 1168 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
@@ -974,13 +1183,15 @@ fi
|
||||
rm -f conftest*
|
||||
ac_cv_prog_CPP="$CPP"
|
||||
fi
|
||||
CPP="$ac_cv_prog_CPP"
|
||||
else
|
||||
ac_cv_prog_CPP="$CPP"
|
||||
fi
|
||||
CPP="$ac_cv_prog_CPP"
|
||||
echo "$ac_t""$CPP" 1>&4
|
||||
|
||||
|
||||
echo $ac_n "checking signed size_t type""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_signed_size_t'+set}'`\" = set"; then
|
||||
echo $ac_n "checking for signed size_t type""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_signed_size_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
echo '#include <stddef.h>
|
||||
@@ -1002,12 +1213,12 @@ if test $libc_cv_signed_size_t = yes; then
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking libc-friendly stddef.h""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_friendly_stddef'+set}'`\" = set"; then
|
||||
echo $ac_n "checking for libc-friendly stddef.h""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_friendly_stddef'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1011 "configure"
|
||||
#line 1222 "configure"
|
||||
#include "confdefs.h"
|
||||
#define __need_size_t
|
||||
#define __need_wchar_t
|
||||
@@ -1041,7 +1252,7 @@ override stddef.h = # The installed <stddef.h> seems to be libc-friendly."
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether we need to use -P to assemble .S files""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_need_minus_P'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'libc_cv_need_minus_P'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
cat > conftest.S <<EOF
|
||||
@@ -1062,6 +1273,103 @@ if test $libc_cv_need_minus_P = yes; then
|
||||
asm-CPPFLAGS = -P # The assembler can't grok cpp's # line directives."
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for assembler global-symbol directive""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_asm_global_directive'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
libc_cv_asm_global_directive=UNKNOWN
|
||||
for ac_globl in .globl .global; do
|
||||
cat > conftest.s <<EOF
|
||||
.text
|
||||
${ac_globl} foo
|
||||
foo: .long 0
|
||||
EOF
|
||||
if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
|
||||
libc_cv_asm_global_directive=${ac_globl}
|
||||
fi
|
||||
rm -f conftest*
|
||||
test $libc_cv_asm_global_directive != UNKNOWN && break
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_asm_global_directive" 1>&4
|
||||
if test $libc_cv_asm_global_directive = UNKNOWN; then
|
||||
{ echo "configure: error: cannot determine asm global directive" 1>&2; exit 1; }
|
||||
else
|
||||
cat >> confdefs.h <<EOF
|
||||
#define ASM_GLOBAL_DIRECTIVE ${libc_cv_asm_global_directive}
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for .set assembler directive""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_asm_set_directive'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
cat > conftest.s <<EOF
|
||||
.text
|
||||
foo: .long 0
|
||||
.set glibc_conftest_frobozz,foo
|
||||
$libc_cv_asm_global_directive glibc_conftest_frobozz
|
||||
EOF
|
||||
# The alpha-dec-osf1 assembler gives only a warning for `.set'
|
||||
# (but it doesn't work), so we must do a linking check to be sure.
|
||||
cat > conftest1.c <<\EOF
|
||||
extern int glibc_conftest_frobozz;
|
||||
main () { printf ("%d\n", glibc_conftest_frobozz); }
|
||||
EOF
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||
-o conftest conftest.s conftest1.c 1>&5 2>&5; then
|
||||
libc_cv_asm_set_directive=yes
|
||||
else
|
||||
libc_cv_asm_set_directive=no
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_asm_set_directive" 1>&4
|
||||
if test $libc_cv_asm_set_directive = yes; then
|
||||
cat >> confdefs.h <<\EOF
|
||||
#define HAVE_ASM_SET_DIRECTIVE 1
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
if test $elf != yes; then
|
||||
echo $ac_n "checking for .init and .fini sections""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_have_initfini'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1345 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
int main() { return 0; }
|
||||
int t() {
|
||||
asm (".section .init");
|
||||
asm (".section .fini");
|
||||
; return 0; }
|
||||
EOF
|
||||
if eval $ac_compile; then
|
||||
rm -rf conftest*
|
||||
libc_cv_have_initfini=yes
|
||||
else
|
||||
rm -rf conftest*
|
||||
libc_cv_have_initfini=no
|
||||
fi
|
||||
rm -f conftest*
|
||||
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_have_initfini" 1>&4
|
||||
if test $libc_cv_have_initfini = yes; then
|
||||
cat >> confdefs.h <<\EOF
|
||||
#define HAVE_INITFINI 1
|
||||
EOF
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
# sysdeps configure fragments may set these with files to be linked below.
|
||||
libc_link_dests=
|
||||
libc_link_sources=
|
||||
@@ -1092,7 +1400,7 @@ if test "$uname" = generic; then
|
||||
fi
|
||||
|
||||
echo $ac_n "checking OS release for uname""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_uname_release'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'libc_cv_uname_release'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
kernel_release=`echo "$kernel_id" | sed 's/^[^0-9.]*\([0-9.]*\).*$/\1/'`
|
||||
@@ -1109,11 +1417,11 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_uname_release" 1>&4
|
||||
echo "$ac_t""$libc_cv_uname_release" 1>&4
|
||||
uname_release="$libc_cv_uname_release"
|
||||
|
||||
echo $ac_n "checking OS version for uname""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '${'libc_cv_uname_version'+set}'`\" = set"; then
|
||||
if eval "test \"`echo '$''{'libc_cv_uname_version'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&4
|
||||
else
|
||||
kernel_version=`echo "$kernel_id" | sed 's/^[^#]*#\([0-9]*\).*$/\1/'`
|
||||
@@ -1124,7 +1432,7 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$ac_t""$libc_cv_uname_version" 1>&4
|
||||
echo "$ac_t""$libc_cv_uname_version" 1>&4
|
||||
uname_version="$libc_cv_uname_version"
|
||||
|
||||
config_uname=config-name.h:config-name.in
|
||||
@@ -1133,6 +1441,17 @@ else
|
||||
config_uname=
|
||||
fi
|
||||
|
||||
echo $ac_n "checking stdio selection""... $ac_c" 1>&4
|
||||
|
||||
case $stdio in
|
||||
libio) cat >> confdefs.h <<\EOF
|
||||
#define USE_IN_LIBIO 1
|
||||
EOF
|
||||
;;
|
||||
default) stdio=stdio ;;
|
||||
esac
|
||||
echo "$ac_t""$stdio" 1>&4
|
||||
|
||||
|
||||
if test $gnu_ld = yes; then
|
||||
cat >> confdefs.h <<\EOF
|
||||
@@ -1160,6 +1479,14 @@ EOF
|
||||
fi
|
||||
|
||||
|
||||
if test $shared = default; then
|
||||
if test $gnu_ld = yes; then
|
||||
shared=$elf
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test "`(cd $srcdir; pwd)`" = "`pwd`"; then
|
||||
config_makefile=
|
||||
else
|
||||
@@ -1167,9 +1494,7 @@ else
|
||||
fi
|
||||
|
||||
trap '' 1 2 15
|
||||
if test -w $cache_file; then
|
||||
echo "updating cache $cache_file"
|
||||
cat > $cache_file <<\EOF
|
||||
cat > confcache <<\EOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests run on this system so they can be shared between configure
|
||||
# scripts and configure runs. It is not useful on other systems.
|
||||
@@ -1189,10 +1514,18 @@ EOF
|
||||
# and sets the high bit in the cache file unless we assign to the vars.
|
||||
(set) 2>&1 |
|
||||
sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
|
||||
>> $cache_file
|
||||
>> confcache
|
||||
if cmp -s $cache_file confcache; then
|
||||
:
|
||||
else
|
||||
echo "not updating unwritable cache $cache_file"
|
||||
if test -w $cache_file; then
|
||||
echo "updating cache $cache_file"
|
||||
cat confcache > $cache_file
|
||||
else
|
||||
echo "not updating unwritable cache $cache_file"
|
||||
fi
|
||||
fi
|
||||
rm -f confcache
|
||||
|
||||
trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
|
||||
|
||||
@@ -1236,7 +1569,7 @@ do
|
||||
echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
|
||||
exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
|
||||
-version | --version | --versio | --versi | --vers | --ver | --ve | --v)
|
||||
echo "$CONFIG_STATUS generated by autoconf version 2.1.1"
|
||||
echo "$CONFIG_STATUS generated by autoconf version 2.7"
|
||||
exit 0 ;;
|
||||
-help | --help | --hel | --he | --h)
|
||||
echo "\$ac_cs_usage"; exit 0 ;;
|
||||
@@ -1247,11 +1580,13 @@ done
|
||||
ac_given_srcdir=$srcdir
|
||||
ac_given_INSTALL="$INSTALL"
|
||||
|
||||
trap 'rm -fr `echo config.make ${config_makefile} ${config_uname} config.h | tr : " "` conftest*; exit 1' 1 2 15
|
||||
trap 'rm -fr `echo "config.make ${config_makefile} ${config_uname} config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
|
||||
EOF
|
||||
cat >> $CONFIG_STATUS <<EOF
|
||||
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g;
|
||||
s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
|
||||
s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
|
||||
$ac_vpsub
|
||||
$extrasub
|
||||
s%@CFLAGS@%$CFLAGS%g
|
||||
@@ -1263,6 +1598,18 @@ s%@LIBS@%$LIBS%g
|
||||
s%@exec_prefix@%$exec_prefix%g
|
||||
s%@prefix@%$prefix%g
|
||||
s%@program_transform_name@%$program_transform_name%g
|
||||
s%@bindir@%$bindir%g
|
||||
s%@sbindir@%$sbindir%g
|
||||
s%@libexecdir@%$libexecdir%g
|
||||
s%@datadir@%$datadir%g
|
||||
s%@sysconfdir@%$sysconfdir%g
|
||||
s%@sharedstatedir@%$sharedstatedir%g
|
||||
s%@localstatedir@%$localstatedir%g
|
||||
s%@libdir@%$libdir%g
|
||||
s%@includedir@%$includedir%g
|
||||
s%@oldincludedir@%$oldincludedir%g
|
||||
s%@infodir@%$infodir%g
|
||||
s%@mandir@%$mandir%g
|
||||
s%@host@%$host%g
|
||||
s%@host_alias@%$host_alias%g
|
||||
s%@host_cpu@%$host_cpu%g
|
||||
@@ -1280,13 +1627,18 @@ s%@CC@%$CC%g
|
||||
s%@AR@%$AR%g
|
||||
s%@RANLIB@%$RANLIB%g
|
||||
s%@CPP@%$CPP%g
|
||||
s%@libc_cv_have_initfini@%$libc_cv_have_initfini%g
|
||||
s%@uname_sysname@%$uname_sysname%g
|
||||
s%@uname_release@%$uname_release%g
|
||||
s%@uname_version@%$uname_version%g
|
||||
s%@stdio@%$stdio%g
|
||||
s%@gnu_ld@%$gnu_ld%g
|
||||
s%@gnu_as@%$gnu_as%g
|
||||
s%@elf@%$elf%g
|
||||
s%@weak@%$weak%g
|
||||
s%@shared@%$shared%g
|
||||
s%@profile@%$profile%g
|
||||
s%@omitfp@%$omitfp%g
|
||||
|
||||
CEOF
|
||||
EOF
|
||||
@@ -1385,7 +1737,7 @@ EOF
|
||||
|
||||
# Transform confdefs.h into a sed script conftest.vals that substitutes
|
||||
# the proper values into config.h.in to produce config.h. And first:
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
# Protect against being in an unquoted here document in config.status.
|
||||
rm -f conftest.vals
|
||||
cat > conftest.hdr <<\EOF
|
||||
|
||||
+180
-68
@@ -1,6 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_REVISION([$Id$])
|
||||
AC_PREREQ(2.1)dnl dnl Minimum Autoconf version required.
|
||||
Dnl Process this file with autoconf to produce a configure script.
|
||||
AC_REVISION([$CVSid$])
|
||||
AC_PREREQ(2.4.2)dnl dnl Minimum Autoconf version required.
|
||||
AC_INIT(features.h)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -18,23 +18,61 @@ yes) AC_MSG_ERROR(--with-gmp requires an argument; use --with-gmp=DIRECTORY) ;;
|
||||
gmp-srcdir = $withval" ;;
|
||||
esac
|
||||
])
|
||||
# Check for a --with-gettext argument and set gettext-srcdir in config.make.
|
||||
AC_ARG_WITH(gettext, dnl
|
||||
--with-gettext=DIR find GNU gettext source code in DIR (not needed),
|
||||
[dnl
|
||||
case "$with_gettext" in
|
||||
yes)
|
||||
AC_MSG_ERROR(--with-gettext requires an argument; use --with-gettext=DIR) ;;
|
||||
''|no) ;;
|
||||
*)
|
||||
config_vars="$config_vars
|
||||
gettext-srcdir = $withval" ;;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl Arguments to specify presence of other packages/features.
|
||||
AC_ARG_WITH(fp, dnl
|
||||
--with-fp if using floating-point hardware,
|
||||
with_fp=$withval, with_fp=yes)
|
||||
AC_ARG_WITH(gnu-binutils, dnl
|
||||
--with-gnu-binutils if using GNU binutils (as and ld),
|
||||
gnu_binutils=yes, gnu_binutils=no)
|
||||
gnu_binutils=$withval, gnu_binutils=no)
|
||||
AC_ARG_WITH(gnu-ld, dnl
|
||||
--with-gnu-ld if using GNU ld (in the binutils package),
|
||||
gnu_ld=yes, gnu_ld=no)
|
||||
gnu_ld=$withval, gnu_ld=no)
|
||||
AC_ARG_WITH(gnu-as, dnl
|
||||
--with-gnu-as if using GNU as (in the binutils package),
|
||||
gnu_as=yes, gnu_as=no)
|
||||
gnu_as=$withval, gnu_as=no)
|
||||
test $gnu_binutils = yes && gnu_as=yes gnu_ld=yes
|
||||
AC_ARG_WITH(elf, dnl
|
||||
--with-elf if using the ELF object format,
|
||||
elf=yes, elf=no)
|
||||
elf=$withval, elf=no)
|
||||
AC_ARG_WITH(weak-symbols, dnl
|
||||
--with-weak-symbols if weak symbols are available in as and ld,
|
||||
weak=yes, weak=no)
|
||||
weak=$withval, weak=no)
|
||||
|
||||
AC_ARG_ENABLE(libio, dnl
|
||||
[ --enable-libio build in GNU libio instead of GNU stdio],
|
||||
[if test $enableval = yes; then
|
||||
stdio=libio
|
||||
else
|
||||
stdio=stdio
|
||||
fi],
|
||||
stdio=default)
|
||||
|
||||
dnl Arguments to enable or disable building the shared, profiled, and
|
||||
dnl -fomit-frame-pointer libraries.
|
||||
AC_ARG_ENABLE(shared, dnl
|
||||
[ --enable-shared build shared library [default=yes if GNU ld & ELF]],
|
||||
shared=$enableval, shared=default)
|
||||
AC_ARG_ENABLE(profile, dnl
|
||||
[ --enable-profile build profiled library [default=yes]],
|
||||
profile=$enableval, profile=yes)
|
||||
AC_ARG_ENABLE(omitfp, dnl
|
||||
[ --enable-omitfp build undebuggable optimized library [default=no]],
|
||||
omitfp=$enableval, omitfp=no)
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
# We keep the original values in `$config_*' and never modify them, so we
|
||||
@@ -42,9 +80,21 @@ AC_CANONICAL_HOST
|
||||
# $machine, $vendor, and $os, and changes them whenever convenient.
|
||||
config_machine=$host_cpu config_vendor=$host_vendor config_os=$host_os
|
||||
|
||||
# Some configurations imply other options.
|
||||
case "$host_os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
# These systems always use GNU tools.
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$host_os" in
|
||||
gnu* | linux* | sysv4* | solaris2*)
|
||||
# These systems always use the ELF format.
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
# Compute the list of sysdep directories for this configuration.
|
||||
sysdep_dir=$srcdir/sysdeps
|
||||
AC_MSG_CHECKING(sysdep dirs)
|
||||
AC_CACHE_VAL(libc_cv_sysdirs, [dnl
|
||||
AC_CACHE_CHECK(sysdep dirs, libc_cv_sysdirs, [dnl
|
||||
machine=$config_machine
|
||||
vendor=$config_vendor
|
||||
os=$config_os
|
||||
@@ -54,22 +104,18 @@ changequote(,)dnl
|
||||
# Expand the configuration machine name into a subdirectory by architecture
|
||||
# type and particular chip.
|
||||
case "$machine" in
|
||||
i[345]86)
|
||||
machine=i386/$machine ;;
|
||||
sparc[6789])
|
||||
machine=sparc/$machine ;;
|
||||
m68k)
|
||||
machine=m68k/m68020 ;;
|
||||
m680?0)
|
||||
machine=m68k/$machine ;;
|
||||
m88k)
|
||||
machine=m88k/m88100 ;;
|
||||
m88???)
|
||||
machine=m88k/$machine ;;
|
||||
mips64*)
|
||||
machine=mips/mips64/$machine ;;
|
||||
mips*)
|
||||
machine=mips/$machine ;;
|
||||
a29k | am29000) machine=a29k ;;
|
||||
alpha*) machine=alpha/$machine ;;
|
||||
hppa*) machine=hppa/$machine ;;
|
||||
i[345]86) machine=i386/$machine ;;
|
||||
m680?0) machine=m68k/$machine ;;
|
||||
m68k) machine=m68k/m68020 ;;
|
||||
m88???) machine=m88k/$machine ;;
|
||||
m88k) machine=m88k/m88100 ;;
|
||||
mips*) machine=mips/$machine ;;
|
||||
mips64*) machine=mips/mips64/$machine ;;
|
||||
sparc[6789]) machine=sparc/$machine ;;
|
||||
supersparc) machine=sparc/sparc8 ;;
|
||||
esac
|
||||
|
||||
# Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1.
|
||||
@@ -78,11 +124,11 @@ os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`"
|
||||
case "$os" in
|
||||
gnu*)
|
||||
base_os=mach/hurd ;;
|
||||
netbsd* | 386bsd*)
|
||||
netbsd* | 386bsd* | freebsd* | bsdi*)
|
||||
base_os=unix/bsd/bsd4.4 ;;
|
||||
osf1* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
|
||||
osf* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
|
||||
base_os=unix/bsd ;;
|
||||
linux* | sysv* | isc* | esix* | sco* | minix* | irix4*)
|
||||
sysv* | isc* | esix* | sco* | minix* | irix4* | linux*)
|
||||
base_os=unix/sysv ;;
|
||||
solaris[2-9]*)
|
||||
base_os=unix/sysv/sysv4 ;;
|
||||
@@ -98,7 +144,7 @@ ostry=$os
|
||||
while o=`echo $tail | sed 's/\.[^.]*$//'`; test $o != $tail; do
|
||||
ostry="$ostry /$o"
|
||||
tail=$o
|
||||
done
|
||||
done
|
||||
o=`echo $tail | sed 's/[0-9]*$//'`
|
||||
if test $o != $tail; then
|
||||
ostry="$ostry /$o"
|
||||
@@ -118,6 +164,10 @@ mach=
|
||||
tail=$machine
|
||||
while m=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$m"; do
|
||||
set $m
|
||||
# Prepend the machine's FPU directory unless --without-fp.
|
||||
if test "$with_fp" = yes; then
|
||||
mach="$mach /$1/fpu"
|
||||
fi
|
||||
mach="$mach /$1"
|
||||
tail="$2"
|
||||
done
|
||||
@@ -133,6 +183,7 @@ for b in $base ''; do
|
||||
for o in /$ostry ''; do
|
||||
for m in $mach ''; do
|
||||
try="$m0$b$v$o$m"
|
||||
test -n "$enable_debug_configure" && echo "$0 [DEBUG]: try $try" >&2
|
||||
if test -d $sysdep_dir$try; then
|
||||
sysnames="$sysnames $try"
|
||||
{ test -n "$o" || test -n "$b"; } && os_used=t
|
||||
@@ -153,19 +204,26 @@ fi
|
||||
|
||||
# We have now validated the configuration.
|
||||
|
||||
|
||||
# If using ELF, look for an `elf' subdirectory of each machine directory.
|
||||
# We prepend these rather than inserting them whereever the machine appears
|
||||
# because things specified by the machine's ELF ABI should override
|
||||
# OS-specific things, and should always be the same for any OS on the
|
||||
# machine (otherwise what's the point of an ABI?).
|
||||
if test "$elf" = yes; then
|
||||
elf_dirs=
|
||||
for m in $mach; do
|
||||
if test -d $sysdep_dir$m/elf; then
|
||||
elf_dirs="$elf_dirs $m/elf"
|
||||
fi
|
||||
done
|
||||
sysnames="`echo $elf_dirs | sed -e 's,^/,,' -e 's, /,,g'` $sysnames"
|
||||
fi
|
||||
|
||||
|
||||
# Remove the leading slashes.
|
||||
sysnames="`echo $sysnames | sed -e 's@^/@@' -e 's@ /@ @g'`"
|
||||
|
||||
# Prepend the machine's FPU directory unless --without-fp.
|
||||
if test "$with_fp" = no; then
|
||||
fpu_dirs=
|
||||
for m in $mach; do
|
||||
if test -d $sysdep_dir$m/fpu; then
|
||||
fpu_dirs="$fpu_dirs $m/fpu"
|
||||
fi
|
||||
done
|
||||
sysnames="`echo $fpu_dirs | sed -e 's,^/,,' -e 's, /,,g'` $sysnames"
|
||||
fi
|
||||
|
||||
# Expand the list of system names into a full list of directories
|
||||
# from each element's parent name and Implies file (if present).
|
||||
@@ -226,16 +284,6 @@ $name"
|
||||
done
|
||||
libc_cv_sysdirs="$sysnames"])
|
||||
AC_SUBST(sysnames) sysnames="$libc_cv_sysdirs"
|
||||
AC_MSG_RESULT(${sysnames})
|
||||
|
||||
case "$host_os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$host_os" in
|
||||
gnu*elf* | linux*elf* | sysv4* | solaris2*)
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
AC_PROG_INSTALL
|
||||
if test "$INSTALL" = "${srcdir}/install-sh"; then
|
||||
@@ -243,13 +291,12 @@ if test "$INSTALL" = "${srcdir}/install-sh"; then
|
||||
INSTALL='$(..)./install-sh'
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
AC_CHECK_TOOL(CC, gcc)
|
||||
AC_CHECK_TOOL(AR, ar)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib, :)
|
||||
AC_PROG_CPP
|
||||
AC_CHECK_PROG(AR, ar, ar, ar)
|
||||
AC_PROG_RANLIB
|
||||
|
||||
AC_MSG_CHECKING(signed size_t type)
|
||||
AC_CACHE_VAL(libc_cv_signed_size_t, [dnl
|
||||
AC_CACHE_CHECK(for signed size_t type, libc_cv_signed_size_t, [dnl
|
||||
echo '#include <stddef.h>
|
||||
FOOBAR __SIZE_TYPE__ FOOBAR' > conftest.c
|
||||
if eval "$ac_cpp conftest.c 2>/dev/null" \
|
||||
@@ -259,7 +306,6 @@ else
|
||||
libc_cv_signed_size_t=yes
|
||||
fi
|
||||
rm -f conftest*])
|
||||
AC_MSG_RESULT($libc_cv_signed_size_t)
|
||||
if test $libc_cv_signed_size_t = yes; then
|
||||
dnl Do this by hand instead of AC_DEFINE so can add #undef to avoid warnings.
|
||||
cat >> confdefs.h <<\EOF
|
||||
@@ -268,8 +314,7 @@ if test $libc_cv_signed_size_t = yes; then
|
||||
EOF
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(libc-friendly stddef.h)
|
||||
AC_CACHE_VAL(libc_cv_friendly_stddef, [dnl
|
||||
AC_CACHE_CHECK(for libc-friendly stddef.h, libc_cv_friendly_stddef, [dnl
|
||||
AC_TRY_COMPILE(dnl
|
||||
[#define __need_size_t
|
||||
#define __need_wchar_t
|
||||
@@ -282,14 +327,13 @@ AC_TRY_COMPILE(dnl
|
||||
if (&size == NULL || &wchar == NULL) abort ();],
|
||||
libc_cv_friendly_stddef=yes,
|
||||
libc_cv_friendly_stddef=no)])
|
||||
AC_MSG_RESULT($libc_cv_friendly_stddef)
|
||||
if test $libc_cv_friendly_stddef = yes; then
|
||||
config_vars="$config_vars
|
||||
override stddef.h = # The installed <stddef.h> seems to be libc-friendly."
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(whether we need to use -P to assemble .S files)
|
||||
AC_CACHE_VAL(libc_cv_need_minus_P, [dnl
|
||||
AC_CACHE_CHECK(whether we need to use -P to assemble .S files,
|
||||
libc_cv_need_minus_P, [dnl
|
||||
cat > conftest.S <<EOF
|
||||
#include "confdefs.h"
|
||||
/* Nothing whatsoever. */
|
||||
@@ -300,12 +344,68 @@ else
|
||||
libc_cv_need_minus_P=yes
|
||||
fi
|
||||
rm -f conftest*])
|
||||
AC_MSG_RESULT($libc_cv_need_minus_P)
|
||||
if test $libc_cv_need_minus_P = yes; then
|
||||
config_vars="$config_vars
|
||||
asm-CPPFLAGS = -P # The assembler can't grok cpp's # line directives."
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for assembler global-symbol directive,
|
||||
libc_cv_asm_global_directive, [dnl
|
||||
libc_cv_asm_global_directive=UNKNOWN
|
||||
for ac_globl in .globl .global; do
|
||||
cat > conftest.s <<EOF
|
||||
.text
|
||||
${ac_globl} foo
|
||||
foo: .long 0
|
||||
EOF
|
||||
if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
|
||||
libc_cv_asm_global_directive=${ac_globl}
|
||||
fi
|
||||
rm -f conftest*
|
||||
test $libc_cv_asm_global_directive != UNKNOWN && break
|
||||
done])
|
||||
if test $libc_cv_asm_global_directive = UNKNOWN; then
|
||||
AC_MSG_ERROR(cannot determine asm global directive)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(ASM_GLOBAL_DIRECTIVE, ${libc_cv_asm_global_directive})
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for .set assembler directive, libc_cv_asm_set_directive, [dnl
|
||||
cat > conftest.s <<EOF
|
||||
.text
|
||||
foo: .long 0
|
||||
.set glibc_conftest_frobozz,foo
|
||||
$libc_cv_asm_global_directive glibc_conftest_frobozz
|
||||
EOF
|
||||
# The alpha-dec-osf1 assembler gives only a warning for `.set'
|
||||
# (but it doesn't work), so we must do a linking check to be sure.
|
||||
cat > conftest1.c <<\EOF
|
||||
extern int glibc_conftest_frobozz;
|
||||
main () { printf ("%d\n", glibc_conftest_frobozz); }
|
||||
EOF
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||
-o conftest conftest.s conftest1.c 1>&AC_FD_CC 2>&AC_FD_CC; then
|
||||
libc_cv_asm_set_directive=yes
|
||||
else
|
||||
libc_cv_asm_set_directive=no
|
||||
fi
|
||||
rm -f conftest*])
|
||||
if test $libc_cv_asm_set_directive = yes; then
|
||||
AC_DEFINE(HAVE_ASM_SET_DIRECTIVE)
|
||||
fi
|
||||
|
||||
if test $elf != yes; then
|
||||
AC_CACHE_CHECK(for .init and .fini sections, libc_cv_have_initfini,
|
||||
[AC_TRY_COMPILE(, [asm (".section .init");
|
||||
asm (".section .fini");],
|
||||
libc_cv_have_initfini=yes,
|
||||
libc_cv_have_initfini=no)])
|
||||
AC_SUBST(libc_cv_have_initfini)dnl
|
||||
if test $libc_cv_have_initfini = yes; then
|
||||
AC_DEFINE(HAVE_INITFINI)
|
||||
fi
|
||||
fi
|
||||
|
||||
# sysdeps configure fragments may set these with files to be linked below.
|
||||
libc_link_dests=
|
||||
libc_link_sources=
|
||||
@@ -347,8 +447,7 @@ AC_DEFUN(LIBC_KERNEL_ID, [dnl
|
||||
fi
|
||||
])dnl
|
||||
|
||||
AC_MSG_CHECKING(OS release for uname)
|
||||
AC_CACHE_VAL(libc_cv_uname_release, [dnl
|
||||
AC_CACHE_CHECK(OS release for uname, libc_cv_uname_release, [dnl
|
||||
AC_REQUIRE([LIBC_KERNEL_ID])dnl
|
||||
changequote(,)dnl
|
||||
kernel_release=`echo "$kernel_id" | sed 's/^[^0-9.]*\([0-9.]*\).*$/\1/'`
|
||||
@@ -364,11 +463,9 @@ changequote([,])dnl
|
||||
else
|
||||
libc_cv_uname_release=unknown
|
||||
fi])
|
||||
AC_MSG_RESULT($libc_cv_uname_release)
|
||||
uname_release="$libc_cv_uname_release"
|
||||
|
||||
AC_MSG_CHECKING(OS version for uname)
|
||||
AC_CACHE_VAL(libc_cv_uname_version, [dnl
|
||||
AC_CACHE_CHECK(OS version for uname, libc_cv_uname_version, [dnl
|
||||
AC_REQUIRE([LIBC_KERNEL_ID])dnl
|
||||
changequote(,)dnl
|
||||
kernel_version=`echo "$kernel_id" | sed 's/^[^#]*#\([0-9]*\).*$/\1/'`
|
||||
@@ -378,7 +475,6 @@ changequote([,])dnl
|
||||
else
|
||||
libc_cv_uname_version=unknown
|
||||
fi])
|
||||
AC_MSG_RESULT($libc_cv_uname_version)
|
||||
uname_version="$libc_cv_uname_version"
|
||||
|
||||
AC_SUBST(uname_sysname) AC_SUBST(uname_release) AC_SUBST(uname_version)dnl
|
||||
@@ -388,6 +484,14 @@ else
|
||||
config_uname=
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(stdio selection)
|
||||
AC_SUBST(stdio)
|
||||
case $stdio in
|
||||
libio) AC_DEFINE(USE_IN_LIBIO) ;;
|
||||
default) stdio=stdio ;;
|
||||
esac
|
||||
AC_MSG_RESULT($stdio)
|
||||
|
||||
AC_SUBST(gnu_ld) AC_SUBST(gnu_as) AC_SUBST(elf) AC_SUBST(weak)
|
||||
if test $gnu_ld = yes; then
|
||||
AC_DEFINE(HAVE_GNU_LD)
|
||||
@@ -402,6 +506,14 @@ if test $weak = yes; then
|
||||
AC_DEFINE(HAVE_WEAK_SYMBOLS)
|
||||
fi
|
||||
|
||||
AC_SUBST(shared)
|
||||
if test $shared = default; then
|
||||
if test $gnu_ld = yes; then
|
||||
shared=$elf
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(profile)
|
||||
AC_SUBST(omitfp)
|
||||
|
||||
if test "`(cd $srcdir; pwd)`" = "`pwd`"; then
|
||||
config_makefile=
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
+32
-19
@@ -1,6 +1,6 @@
|
||||
# Makefile for csu code for GNU C library.
|
||||
|
||||
# Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
# The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -20,18 +20,21 @@
|
||||
|
||||
# This directory contains the C startup code (that which calls main). This
|
||||
# consists of the startfile, built from start.c and installed as crt0.o
|
||||
# (traditionally) or crt1.o (for ELF); and some initialization code which
|
||||
# is in the C library itself. In ELF we also install crti.o and crtn.o,
|
||||
# special "initializer" and "finalizer" files in used in the link to make
|
||||
# the .init and .fini sections work right; both these files are built (in
|
||||
# an arcane manner) from initfini.c.
|
||||
# (traditionally) or crt1.o (for ELF). In ELF we also install crti.o and
|
||||
# crtn.o, special "initializer" and "finalizer" files in used in the link
|
||||
# to make the .init and .fini sections work right; both these files are
|
||||
# built (in an arcane manner) from initfini.c.
|
||||
|
||||
subdir := csu
|
||||
|
||||
csu-dummies = $(filter-out $(start-installed-name),crt1.o Mcrt1.o)
|
||||
extra-objs = start.o $(start-installed-name) $(csu-dummies)
|
||||
omit-deps = $(patsubst %.o,%,$(start-installed-name) $(csu-dummies))
|
||||
install-lib = $(start-installed-name) $(csu-dummies)
|
||||
extra-objs = start.o gmon-start.o \
|
||||
$(start-installed-name) g$(start-installed-name) \
|
||||
$(csu-dummies)
|
||||
omit-deps = $(patsubst %.o,%,$(start-installed-name) g$(start-installed-name) \
|
||||
$(csu-dummies))
|
||||
install-lib = $(start-installed-name) g$(start-installed-name) \
|
||||
$(csu-dummies)
|
||||
distribute = initfini.c
|
||||
|
||||
all: # Make this the default target; it will be defined in Rules.
|
||||
@@ -45,17 +48,21 @@ start-installed-name = crt0.o
|
||||
|
||||
else
|
||||
|
||||
# In the ELF universe, crt0.o is called crt1.o, and there are
|
||||
# In the ELF universe, crt0.o is called crt1.o, and there are
|
||||
# some additional bizarre files.
|
||||
start-installed-name = crt1.o
|
||||
have-initfini = yes
|
||||
|
||||
endif
|
||||
|
||||
ifeq (yes,$(have-initfini))
|
||||
|
||||
CPPFLAGS += -DHAVE_INITFINI
|
||||
|
||||
# These are the special initializer/finalizer files. They are always the
|
||||
# first and last file in the link. crti.o ... crtn.o are used for normal
|
||||
# linking; they define the global "functions" _init and _fini to run the
|
||||
# .init and .fini sections. crti_s.o ... crtn_s.o are for making shared
|
||||
# library objects; they put the prologue/epilogue code into the .init and
|
||||
# .fini sections, but define no global symbols.
|
||||
crtstuff = crti crtn crti_s crtn_s
|
||||
# first and last file in the link. crti.o ... crtn.o define the global
|
||||
# "functions" _init and _fini to run the .init and .fini sections.
|
||||
crtstuff = crti crtn
|
||||
|
||||
install-lib += $(crtstuff:=.o)
|
||||
extra-objs += $(crtstuff:=.o)
|
||||
@@ -67,14 +74,12 @@ omit-deps += $(crtstuff)
|
||||
# disable emission of .size directives and debugging information, since
|
||||
# they will get confused by the splitting of the output we do.
|
||||
$(objpfx)cr%i.s $(objpfx)cr%n.s: initfini.c; $(initfini)
|
||||
$(objpfx)cr%i_s.s $(objpfx)cr%n_s.s: initfini.c; $(initfini)
|
||||
|
||||
define initfini
|
||||
-rm -f $(objpfx)crtcommon.tmp
|
||||
(echo 'cat > crtcommon.tmp <<\EOF_common'; \
|
||||
$(CC) $< $(CPPFLAGS) $(CFLAGS) \
|
||||
$(patsubst %,-DGLOBAL=static,$(filter %_s.s,$@)) \
|
||||
-finhibit-size-directive -g0 -S -o -; \
|
||||
-fPIC -finhibit-size-directive -g0 -S -o -; \
|
||||
echo 'EOF_common') | (cd $(@D); $(SHELL))
|
||||
cat $(objpfx)crtcommon.tmp >> $(objpfx)crti.s-new
|
||||
cat $(objpfx)crtcommon.tmp >> $(objpfx)crtn.s-new
|
||||
@@ -87,11 +92,19 @@ endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
ifndef start-installed-name-rule
|
||||
# The startfile is installed under different names, so we just call our
|
||||
# source file `start.c' and copy to the installed name after compiling.
|
||||
$(objpfx)$(start-installed-name): $(objpfx)start.o
|
||||
-rm -f $@
|
||||
ln $< $@
|
||||
endif
|
||||
|
||||
# The profiling startfile is made by linking together the normal
|
||||
# startfile with gmon-start.o, which defines a constructor function
|
||||
# to turn on profiling code at startup.
|
||||
$(objpfx)g$(start-installed-name): $(objpfx)start.o $(objpfx)gmon-start.o
|
||||
$(CC) -nostdlib -nostartfiles -r -o $@ $^
|
||||
|
||||
# These extra files are sometimes expected by system standard linking
|
||||
# procedures, but we have nothing for them to do. So compile empty files.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Code to enable profiling at program startup.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/gmon.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Beginning and end of our code segment. */
|
||||
extern void _start (void), etext (void);
|
||||
|
||||
#ifndef HAVE_INITFINI
|
||||
/* This function gets called at startup by the normal constructor
|
||||
mechanism. We link this file together with start.o to produce gcrt1.o,
|
||||
so this constructor will be first in the list. */
|
||||
|
||||
void __gmon_start__ (void) __attribute__ ((constructor));
|
||||
#else
|
||||
/* In ELF and COFF, we cannot use the normal constructor mechanism to call
|
||||
__gmon_start__ because gcrt1.o appears before crtbegin.o in the link.
|
||||
Instead crti.o calls it specially (see initfini.c). */
|
||||
#endif
|
||||
|
||||
void
|
||||
__gmon_start__ (void)
|
||||
{
|
||||
/* Start keeping profiling records. */
|
||||
monstartup ((u_long) &_start, (u_long) &etext);
|
||||
|
||||
/* Call _mcleanup before exitting; it will write out gmon.out from the
|
||||
collected data. */
|
||||
atexit (&_mcleanup);
|
||||
}
|
||||
|
||||
+33
-14
@@ -34,31 +34,50 @@ Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* We are compiled with -DGLOBAL=static to generate the versions used for
|
||||
shared libraries' .init and .fini sections, which do not have entry
|
||||
point symbols. */
|
||||
#ifndef GLOBAL
|
||||
#define GLOBAL
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ELF
|
||||
/* These declarations make the functions go in the right sections when
|
||||
we define them below. GCC syntax does not allow the attribute
|
||||
specifications to be in the function definitions themselves. */
|
||||
GLOBAL void _init (void) __attribute__ ((section (".init")));
|
||||
GLOBAL void _fini (void) __attribute__ ((section (".fini")));
|
||||
void _init (void) __attribute__ ((section (".init")));
|
||||
void _fini (void) __attribute__ ((section (".fini")));
|
||||
|
||||
#define SECTION(x) /* Put nothing extra before the defn. */
|
||||
|
||||
#else
|
||||
/* Some non-ELF systems support .init and .fini sections,
|
||||
but the __attribute__ syntax only works for ELF. */
|
||||
#define SECTION(x) asm (".section " x);
|
||||
#endif
|
||||
|
||||
/* End the here document containing the initial common code.
|
||||
Then move the output file crtcommon.tmp to crti.s-new and crtn.s-new. */
|
||||
asm ("\nEOF_common\n\
|
||||
mv -f crtcommon.tmp crti.s-new\n\
|
||||
cp -f crti.s-new crtn.s-new");
|
||||
rm -f crti.s-new crtn.s-new\n\
|
||||
mv crtcommon.tmp crti.s-new\n\
|
||||
cp crti.s-new crtn.s-new");
|
||||
|
||||
/* Append the .init prologue to crti.s-new. */
|
||||
asm ("cat >> crti.s-new <<\\EOF.crti.init");
|
||||
GLOBAL void
|
||||
|
||||
SECTION (".init")
|
||||
void
|
||||
_init (void)
|
||||
{
|
||||
(void) &_init; /* Don't optimize out the function! */
|
||||
/* We cannot use the normal constructor mechanism in gcrt1.o because it
|
||||
appears before crtbegin.o in the link, so the header elt of .ctors
|
||||
would come after the elt for __gmon_start__. One approach is for
|
||||
gcrt1.o to reference a symbol which would be defined by some library
|
||||
module which has a constructor; but then user code's constructors
|
||||
would come first, and not be profiled. */
|
||||
extern volatile void __gmon_start__ (void) __attribute__ ((weak));
|
||||
/* This volatile variable is necessary to avoid GCC optimizing
|
||||
out the test. */
|
||||
register volatile void (*g) (void) = &__gmon_start__;
|
||||
weak_symbol (__gmon_start__)
|
||||
if (g)
|
||||
(*g) ();
|
||||
|
||||
/* End the here document containing the .init prologue code.
|
||||
Then fetch the .section directive just written and append that
|
||||
to crtn.s-new, followed by the function epilogue. */
|
||||
@@ -74,10 +93,10 @@ asm ("\nEOF.crtn.init\
|
||||
\n\
|
||||
cat >> crti.s-new <<\\EOF.crti.fini");
|
||||
|
||||
GLOBAL void
|
||||
SECTION (".fini")
|
||||
void
|
||||
_fini (void)
|
||||
{
|
||||
(void) &_fini; /* Don't optimize out the function! */
|
||||
/* End the here document containing the .fini prologue code.
|
||||
Then fetch the .section directive just written and append that
|
||||
to crtn.s-new, followed by the function epilogue. */
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
+11
-10
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -16,15 +16,16 @@ License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <ansidecl.h>
|
||||
#include <ctype.h>
|
||||
#include <localeinfo.h>
|
||||
#include "../locale/localeinfo.h"
|
||||
|
||||
/* Defined in locale/locale-C-ct.c. */
|
||||
extern CONST unsigned short int __ctype_b_C[];
|
||||
extern CONST short int __ctype_tolower_C[];
|
||||
extern CONST short int __ctype_toupper_C[];
|
||||
/* Defined in locale/C-ctype.c. */
|
||||
extern const char _nl_C_LC_CTYPE_class[];
|
||||
extern const char _nl_C_LC_CTYPE_toupper[];
|
||||
extern const char _nl_C_LC_CTYPE_tolower[];
|
||||
|
||||
CONST unsigned short int *__ctype_b = __ctype_b_C + 1;
|
||||
CONST short int *__ctype_tolower = __ctype_tolower_C + 1;
|
||||
CONST short int *__ctype_toupper = __ctype_toupper_C + 1;
|
||||
#define b(u,x) (((u int *) _nl_C_LC_CTYPE_##x) + 128);
|
||||
|
||||
const unsigned short int *__ctype_b = b(unsigned short, class);
|
||||
const int *__ctype_tolower = b(, tolower);
|
||||
const int *__ctype_toupper = b(, toupper);
|
||||
|
||||
+41
-29
@@ -27,41 +27,53 @@ Cambridge, MA 02139, USA. */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* These are all the characteristics of characters. All the
|
||||
interdependencies (such as that an alphabetic is an uppercase or a
|
||||
lowercase) are here. If there get to be more than
|
||||
(sizeof (unsigned short int) * CHAR_BIT) distinct characteristics,
|
||||
many things must be changed that use `unsigned short int's. */
|
||||
/* These are all the characteristics of characters.
|
||||
If there get to be more than 16 distinct characteristics,
|
||||
many things must be changed that use `unsigned short int's.
|
||||
|
||||
The characteristics are stored always in network byte order (big
|
||||
endian). We define the bit value interpretations here dependent on the
|
||||
machine's byte order. */
|
||||
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define _ISbit(bit) (1 << bit)
|
||||
#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
|
||||
#define _ISbit(bit) (bit < 8 ? ((1 << bit) << 8) : ((1 << bit) >> 8))
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
_ISupper = 1 << 0, /* UPPERCASE. */
|
||||
_ISlower = 1 << 1, /* lowercase. */
|
||||
_IScntrl = 1 << 2, /* Control character. */
|
||||
_ISdigit = 1 << 3, /* Numeric. */
|
||||
_ISspace = 1 << 4, /* Whitespace. */
|
||||
_IShex = 1 << 5, /* A - F, a - f. */
|
||||
_ISpunct = 1 << 6, /* Punctuation. */
|
||||
_NOgraph = 1 << 7, /* Printing but nongraphical. */
|
||||
_ISblank = 1 << 8, /* Blank (usually SPC and TAB). */
|
||||
_ISalpha = 1 << 9, /* Alphabetic. */
|
||||
_ISalnum = _ISalpha | _ISdigit, /* Alphanumeric. */
|
||||
_ISxdigit = _ISdigit | _IShex, /* Hexadecimal numeric. */
|
||||
_ISgraph = _ISalnum | _ISpunct, /* Graphical. */
|
||||
_ISprint = _ISgraph | _NOgraph /* Printing. */
|
||||
_ISupper = _ISbit (0), /* UPPERCASE. */
|
||||
_ISlower = _ISbit (1), /* lowercase. */
|
||||
_ISalpha = _ISbit (2), /* Alphabetic. */
|
||||
_ISdigit = _ISbit (3), /* Numeric. */
|
||||
_ISxdigit = _ISbit (4), /* Hexadecimal numeric. */
|
||||
_ISspace = _ISbit (5), /* Whitespace. */
|
||||
_ISprint = _ISbit (6), /* Printing. */
|
||||
_ISgraph = _ISbit (7), /* Graphical. */
|
||||
_ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
|
||||
_IScntrl = _ISbit (9), /* Control character. */
|
||||
_ISpunct = _ISbit (10), /* Punctuation. */
|
||||
|
||||
/* The following are defined in POSIX.2 as being combinations of the
|
||||
classes above. */
|
||||
_ISalnum = _ISalpha | _ISdigit /* Alphanumeric. */
|
||||
};
|
||||
|
||||
/* These are defined in localeinfo.c.
|
||||
/* These are defined in ctype-info.c.
|
||||
The declarations here must match those in localeinfo.h.
|
||||
|
||||
These point to the second element ([1]) of arrays of size (UCHAR_MAX + 1).
|
||||
EOF is -1, so [EOF] is the first element of the original array.
|
||||
ANSI requires that the ctype functions work for `unsigned char' values
|
||||
and for EOF. The case conversion arrays are of `short int's rather than
|
||||
`unsigned char's because tolower (EOF) must be EOF, which doesn't fit
|
||||
into an `unsigned char'. */
|
||||
These point into arrays of 384, so they can be indexed by any `unsigned
|
||||
char' value [0,255]; by EOF (-1); or by any `signed char' value
|
||||
[-128,-1). ANSI requires that the ctype functions work for `unsigned
|
||||
char' values and for EOF; we also support negative `signed char' values
|
||||
for broken old programs. The case conversion arrays are of `int's
|
||||
rather than `unsigned char's because tolower (EOF) must be EOF, which
|
||||
doesn't fit into an `unsigned char'. */
|
||||
extern __const unsigned short int *__ctype_b; /* Characteristics. */
|
||||
extern __const short int *__ctype_tolower; /* Case conversions. */
|
||||
extern __const short int *__ctype_toupper; /* Case conversions. */
|
||||
extern __const int *__ctype_tolower; /* Case conversions. */
|
||||
extern __const int *__ctype_toupper; /* Case conversions. */
|
||||
|
||||
#define __isctype(c, type) \
|
||||
(__ctype_b[(int) (c)] & (unsigned short int) type)
|
||||
@@ -115,7 +127,7 @@ extern int toascii __P ((int __c));
|
||||
#endif /* Use SVID or use misc. */
|
||||
|
||||
#ifdef __USE_SVID
|
||||
/* These are the same as `toupper' and and `tolower'. */
|
||||
/* These are the same as `toupper' and `tolower'. */
|
||||
__exctype (_toupper);
|
||||
__exctype (_tolower);
|
||||
#endif
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Makefile for 4.4BSD db code in GNU C library.
|
||||
# This code is taken verbatim from the BSD db 1.85 package. Only this
|
||||
# Makefile and compat.h were written for GNU libc, and the header files
|
||||
# moved up to this directory.
|
||||
|
||||
subdir = db
|
||||
|
||||
dbdirs = btree db hash mpool recno
|
||||
vpath %.c $(dbdirs)
|
||||
|
||||
routines := bt_close bt_conv bt_debug bt_delete bt_get bt_open bt_overflow \
|
||||
bt_page bt_put bt_search bt_seq bt_split bt_utils \
|
||||
db \
|
||||
hash hash_bigkey hash_buf hash_func hash_log2 hash_page \
|
||||
ndbm \
|
||||
mpool \
|
||||
rec_close rec_delete rec_get rec_open rec_put rec_search \
|
||||
rec_seq rec_utils
|
||||
|
||||
headers := db.h mpool.h ndbm.h
|
||||
distribute := compat.h \
|
||||
btree/btree.h btree/extern.h \
|
||||
hash/extern.h hash/hash.h hash/page.h \
|
||||
recno/extern.h recno/recno.h
|
||||
|
||||
include ../Rules
|
||||
|
||||
CPPFLAGS += -D__DBINTERFACE_PRIVATE
|
||||
@@ -0,0 +1,182 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_close.c 8.7 (Berkeley) 8/17/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static int bt_meta __P((BTREE *));
|
||||
|
||||
/*
|
||||
* BT_CLOSE -- Close a btree.
|
||||
*
|
||||
* Parameters:
|
||||
* dbp: pointer to access method
|
||||
*
|
||||
* Returns:
|
||||
* RET_ERROR, RET_SUCCESS
|
||||
*/
|
||||
int
|
||||
__bt_close(dbp)
|
||||
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(dbp, flags)
|
||||
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(t)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_conv.c 8.5 (Berkeley) 8/17/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static void mswap __P((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(t, pg, pp)
|
||||
void *t;
|
||||
pgno_t pg;
|
||||
void *pp;
|
||||
{
|
||||
PAGE *h;
|
||||
indx_t i, top;
|
||||
u_char 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 *)GETBINTERNAL(h, i);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(pgno_t);
|
||||
if (*(u_char *)p & P_BIGKEY) {
|
||||
p += sizeof(u_char);
|
||||
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 *)GETBLEAF(h, i);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
flags = *(u_char *)p;
|
||||
if (flags & (P_BIGKEY | P_BIGDATA)) {
|
||||
p += sizeof(u_char);
|
||||
if (flags & P_BIGKEY) {
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(pgno_t);
|
||||
P_32_SWAP(p);
|
||||
}
|
||||
if (flags & P_BIGDATA) {
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(pgno_t);
|
||||
P_32_SWAP(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
__bt_pgout(t, pg, pp)
|
||||
void *t;
|
||||
pgno_t pg;
|
||||
void *pp;
|
||||
{
|
||||
PAGE *h;
|
||||
indx_t i, top;
|
||||
u_char 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 *)GETBINTERNAL(h, i);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(pgno_t);
|
||||
if (*(u_char *)p & P_BIGKEY) {
|
||||
p += sizeof(u_char);
|
||||
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 *)GETBLEAF(h, i);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(u_int32_t);
|
||||
flags = *(u_char *)p;
|
||||
if (flags & (P_BIGKEY | P_BIGDATA)) {
|
||||
p += sizeof(u_char);
|
||||
if (flags & P_BIGKEY) {
|
||||
P_32_SWAP(p);
|
||||
p += sizeof(pgno_t);
|
||||
P_32_SWAP(p);
|
||||
}
|
||||
if (flags & P_BIGDATA) {
|
||||
p += sizeof(u_int32_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(pg)
|
||||
PAGE *pg;
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = (char *)pg;
|
||||
P_32_SWAP(p); /* magic */
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p); /* version */
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p); /* psize */
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p); /* free */
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p); /* nrecs */
|
||||
p += sizeof(u_int32_t);
|
||||
P_32_SWAP(p); /* flags */
|
||||
p += sizeof(u_int32_t);
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_debug.c 8.5 (Berkeley) 8/17/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* BT_DUMP -- Dump the tree
|
||||
*
|
||||
* Parameters:
|
||||
* dbp: pointer to the DB
|
||||
*/
|
||||
void
|
||||
__bt_dump(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
BTREE *t;
|
||||
PAGE *h;
|
||||
pgno_t i;
|
||||
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", 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(h)
|
||||
PAGE *h;
|
||||
{
|
||||
BTMETA *m;
|
||||
char *sep;
|
||||
|
||||
m = (BTMETA *)h;
|
||||
(void)fprintf(stderr, "magic %lx\n", m->magic);
|
||||
(void)fprintf(stderr, "version %lu\n", m->version);
|
||||
(void)fprintf(stderr, "psize %lu\n", m->psize);
|
||||
(void)fprintf(stderr, "free %lu\n", m->free);
|
||||
(void)fprintf(stderr, "nrecs %lu\n", m->nrecs);
|
||||
(void)fprintf(stderr, "flags %lu", 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(dbp, pgno)
|
||||
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(h)
|
||||
PAGE *h;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BLEAF *bl;
|
||||
RINTERNAL *ri;
|
||||
RLEAF *rl;
|
||||
indx_t cur, top;
|
||||
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/",
|
||||
*(pgno_t *)bl->bytes,
|
||||
*(u_int32_t *)(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",
|
||||
*(pgno_t *)(bl->bytes + bl->ksize),
|
||||
*(u_int32_t *)(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",
|
||||
*(pgno_t *)rl->bytes,
|
||||
*(u_int32_t *)(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(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
|
||||
extern u_long bt_sortsplit, bt_split;
|
||||
BTREE *t;
|
||||
PAGE *h;
|
||||
pgno_t i, pcont, pinternal, pleaf;
|
||||
u_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)", t->bt_nrecs);
|
||||
(void)fprintf(stderr,
|
||||
"\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
|
||||
pinternal + pleaf + pcont, pleaf, pinternal, 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
|
||||
@@ -0,0 +1,657 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_delete.c 8.13 (Berkeley) 7/28/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static int __bt_bdelete __P((BTREE *, const DBT *));
|
||||
static int __bt_curdel __P((BTREE *, const DBT *, PAGE *, u_int));
|
||||
static int __bt_pdelete __P((BTREE *, PAGE *));
|
||||
static int __bt_relink __P((BTREE *, PAGE *));
|
||||
static int __bt_stkacq __P((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(dbp, key, flags)
|
||||
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, 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, 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(t, hp, c)
|
||||
BTREE *t;
|
||||
PAGE **hp;
|
||||
CURSOR *c;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
EPG *e;
|
||||
EPGNO *parent;
|
||||
PAGE *h;
|
||||
indx_t index;
|
||||
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) {
|
||||
index = parent->index + 1;
|
||||
BT_PUSH(t, h->pgno, index);
|
||||
break;
|
||||
}
|
||||
mpool_put(t->bt_mp, h, 0);
|
||||
}
|
||||
|
||||
/* Restore the stack. */
|
||||
while (level--) {
|
||||
/* Push the next level down onto the stack. */
|
||||
bi = GETBINTERNAL(h, index);
|
||||
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);
|
||||
index = 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) {
|
||||
index = parent->index - 1;
|
||||
BT_PUSH(t, h->pgno, index);
|
||||
break;
|
||||
}
|
||||
mpool_put(t->bt_mp, h, 0);
|
||||
}
|
||||
|
||||
/* Restore the stack. */
|
||||
while (level--) {
|
||||
/* Push the next level down onto the stack. */
|
||||
bi = GETBINTERNAL(h, index);
|
||||
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);
|
||||
|
||||
index = NEXTINDEX(h) - 1;
|
||||
BT_PUSH(t, pgno, index);
|
||||
}
|
||||
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(t, key)
|
||||
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, 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, 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(t, h)
|
||||
BTREE *t;
|
||||
PAGE *h;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
PAGE *pg;
|
||||
EPGNO *parent;
|
||||
indx_t cnt, index, *ip, offset;
|
||||
u_int32_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);
|
||||
|
||||
index = parent->index;
|
||||
bi = GETBINTERNAL(pg, index);
|
||||
|
||||
/* 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 *)pg + pg->upper;
|
||||
memmove(from + nksize, from, (char *)bi - from);
|
||||
pg->upper += nksize;
|
||||
|
||||
/* Adjust indices' offsets, shift the indices down. */
|
||||
offset = pg->linp[index];
|
||||
for (cnt = index, ip = &pg->linp[0]; cnt--; ++ip)
|
||||
if (ip[0] < offset)
|
||||
ip[0] += nksize;
|
||||
for (cnt = NEXTINDEX(pg) - index; --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
|
||||
* index: index on page to delete
|
||||
*
|
||||
* Returns:
|
||||
* RET_SUCCESS, RET_ERROR.
|
||||
*/
|
||||
int
|
||||
__bt_dleaf(t, key, h, index)
|
||||
BTREE *t;
|
||||
const DBT *key;
|
||||
PAGE *h;
|
||||
u_int index;
|
||||
{
|
||||
BLEAF *bl;
|
||||
indx_t cnt, *ip, offset;
|
||||
u_int32_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 == index &&
|
||||
__bt_curdel(t, key, h, index))
|
||||
return (RET_ERROR);
|
||||
|
||||
/* If the entry uses overflow pages, make them available for reuse. */
|
||||
to = bl = GETBLEAF(h, index);
|
||||
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 *)h + h->upper;
|
||||
memmove(from + nbytes, from, (char *)to - from);
|
||||
h->upper += nbytes;
|
||||
|
||||
/* Adjust the indices' offsets, shift the indices down. */
|
||||
offset = h->linp[index];
|
||||
for (cnt = index, ip = &h->linp[0]; cnt--; ++ip)
|
||||
if (ip[0] < offset)
|
||||
ip[0] += nbytes;
|
||||
for (cnt = NEXTINDEX(h) - index; --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 > index)
|
||||
--t->bt_cursor.pg.index;
|
||||
|
||||
return (RET_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bt_curdel --
|
||||
* Delete the cursor.
|
||||
*
|
||||
* Parameters:
|
||||
* t: tree
|
||||
* key: referenced key (or NULL)
|
||||
* h: page
|
||||
* index: index on page to delete
|
||||
*
|
||||
* Returns:
|
||||
* RET_SUCCESS, RET_ERROR.
|
||||
*/
|
||||
static int
|
||||
__bt_curdel(t, key, h, index)
|
||||
BTREE *t;
|
||||
const DBT *key;
|
||||
PAGE *h;
|
||||
u_int index;
|
||||
{
|
||||
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 = index;
|
||||
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 (index > 0) {
|
||||
e.page = h;
|
||||
e.index = index - 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 (index < NEXTINDEX(h) - 1) {
|
||||
e.page = h;
|
||||
e.index = index + 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 (index == 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 (index == 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 = index;
|
||||
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(t, h)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_get.c 8.6 (Berkeley) 7/20/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <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(dbp, key, data, flags)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_open.c 8.10 (Berkeley) 8/17/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* 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/param.h>
|
||||
#include <sys/stat.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 <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef MINPSIZE
|
||||
#define MINPSIZE 128
|
||||
#endif
|
||||
|
||||
static int byteorder __P((void));
|
||||
static int nroot __P((BTREE *));
|
||||
static int tmp __P((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(fname, flags, mode, openinfo, dflags)
|
||||
const char *fname;
|
||||
int flags, mode, dflags;
|
||||
const BTREEINFO *openinfo;
|
||||
{
|
||||
struct stat sb;
|
||||
BTMETA m;
|
||||
BTREE *t;
|
||||
BTREEINFO b;
|
||||
DB *dbp;
|
||||
pgno_t ncache;
|
||||
ssize_t nr;
|
||||
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)) < 0)
|
||||
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, 1) == -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.
|
||||
*/
|
||||
t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
|
||||
(sizeof(indx_t) + NBLEAFDBT(0, 0));
|
||||
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(t)
|
||||
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()
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int fd;
|
||||
char *envtmp;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
envtmp = getenv("TMPDIR");
|
||||
(void)snprintf(path,
|
||||
sizeof(path), "%s/bt.XXXXXX", envtmp ? envtmp : "/tmp");
|
||||
|
||||
(void)sigfillset(&set);
|
||||
(void)sigprocmask(SIG_BLOCK, &set, &oset);
|
||||
if ((fd = mkstemp(path)) != -1)
|
||||
(void)unlink(path);
|
||||
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
return(fd);
|
||||
}
|
||||
|
||||
static int
|
||||
byteorder()
|
||||
{
|
||||
u_int32_t x;
|
||||
u_char *p;
|
||||
|
||||
x = 0x01020304;
|
||||
p = (u_char *)&x;
|
||||
switch (*p) {
|
||||
case 1:
|
||||
return (BIG_ENDIAN);
|
||||
case 4:
|
||||
return (LITTLE_ENDIAN);
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
__bt_fd(dbp)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_overflow.c 8.5 (Berkeley) 7/16/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <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, u_int32_t }
|
||||
* buf: storage address
|
||||
* bufsz: storage size
|
||||
*
|
||||
* Returns:
|
||||
* RET_ERROR, RET_SUCCESS
|
||||
*/
|
||||
int
|
||||
__ovfl_get(t, p, ssz, buf, bufsz)
|
||||
BTREE *t;
|
||||
void *p;
|
||||
size_t *ssz;
|
||||
void **buf;
|
||||
size_t *bufsz;
|
||||
{
|
||||
PAGE *h;
|
||||
pgno_t pg;
|
||||
size_t nb, plen;
|
||||
u_int32_t sz;
|
||||
|
||||
memmove(&pg, p, sizeof(pgno_t));
|
||||
memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_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.
|
||||
*/
|
||||
plen = t->bt_psize - BTDATAOFF;
|
||||
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 *)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(t, dbt, pg)
|
||||
BTREE *t;
|
||||
const DBT *dbt;
|
||||
pgno_t *pg;
|
||||
{
|
||||
PAGE *h, *last;
|
||||
void *p;
|
||||
pgno_t npg;
|
||||
size_t nb, plen;
|
||||
u_int32_t sz;
|
||||
|
||||
/*
|
||||
* Allocate pages and copy the key/data record into them. Store the
|
||||
* number of the first page in the chain.
|
||||
*/
|
||||
plen = t->bt_psize - BTDATAOFF;
|
||||
for (last = NULL, p = dbt->data, sz = dbt->size;;
|
||||
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);
|
||||
memmove((char *)h + BTDATAOFF, p, 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, u_int32_t }
|
||||
*
|
||||
* Returns:
|
||||
* RET_ERROR, RET_SUCCESS
|
||||
*/
|
||||
int
|
||||
__ovfl_delete(t, p)
|
||||
BTREE *t;
|
||||
void *p;
|
||||
{
|
||||
PAGE *h;
|
||||
pgno_t pg;
|
||||
size_t plen;
|
||||
u_int32_t sz;
|
||||
|
||||
memmove(&pg, p, sizeof(pgno_t));
|
||||
memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_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. */
|
||||
for (plen = t->bt_psize - BTDATAOFF;; 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);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_page.c 8.3 (Berkeley) 7/14/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <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(t, h)
|
||||
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;
|
||||
|
||||
/* 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(t, npg)
|
||||
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;
|
||||
return (h);
|
||||
}
|
||||
return (mpool_new(t->bt_mp, npg));
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_put.c 8.8 (Berkeley) 7/26/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static EPG *bt_fast __P((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(dbp, key, data, flags)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
const DBT *data;
|
||||
u_int flags;
|
||||
{
|
||||
BTREE *t;
|
||||
DBT tkey, tdata;
|
||||
EPG *e;
|
||||
PAGE *h;
|
||||
indx_t index, nxtindex;
|
||||
pgno_t pg;
|
||||
u_int32_t nbytes;
|
||||
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(u_int32_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));
|
||||
memmove(db + sizeof(pgno_t),
|
||||
&data->size, sizeof(u_int32_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);
|
||||
index = 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;
|
||||
index = 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, index) == 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, index)) != RET_SUCCESS)
|
||||
return (status);
|
||||
goto success;
|
||||
}
|
||||
|
||||
if (index < (nxtindex = NEXTINDEX(h)))
|
||||
memmove(h->linp + index + 1, h->linp + index,
|
||||
(nxtindex - index) * sizeof(indx_t));
|
||||
h->lower += sizeof(indx_t);
|
||||
|
||||
h->linp[index] = h->upper -= nbytes;
|
||||
dest = (char *)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 >= index)
|
||||
++t->bt_cursor.pg.index;
|
||||
|
||||
if (t->bt_order == NOT)
|
||||
if (h->nextpg == P_INVALID) {
|
||||
if (index == NEXTINDEX(h) - 1) {
|
||||
t->bt_order = FORWARD;
|
||||
t->bt_last.index = index;
|
||||
t->bt_last.pgno = h->pgno;
|
||||
}
|
||||
} else if (h->prevpg == P_INVALID) {
|
||||
if (index == 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, e->index);
|
||||
|
||||
F_SET(t, B_MODIFIED);
|
||||
return (RET_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef STATISTICS
|
||||
u_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(t, key, data, exactp)
|
||||
BTREE *t;
|
||||
const DBT *key, *data;
|
||||
int *exactp;
|
||||
{
|
||||
PAGE *h;
|
||||
u_int32_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);
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_search.c 8.8 (Berkeley) 7/31/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static int __bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
|
||||
static int __bt_sprev __P((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(t, key, exactp)
|
||||
BTREE *t;
|
||||
const DBT *key;
|
||||
int *exactp;
|
||||
{
|
||||
PAGE *h;
|
||||
indx_t base, index, 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 = index = base + (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 = index + 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.
|
||||
*/
|
||||
index = base ? base - 1 : base;
|
||||
|
||||
next: BT_PUSH(t, h->pgno, index);
|
||||
pg = GETBINTERNAL(h, index)->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(t, h, key, exactp)
|
||||
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(t, h, key, exactp)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static int __bt_first __P((BTREE *, const DBT *, EPG *, int *));
|
||||
static int __bt_seqadv __P((BTREE *, EPG *, int));
|
||||
static int __bt_seqset __P((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(dbp, key, data, flags)
|
||||
const DB *dbp;
|
||||
DBT *key, *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, flags);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case R_FIRST:
|
||||
case R_LAST:
|
||||
case R_CURSOR:
|
||||
status = __bt_seqset(t, &e, key, flags);
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (RET_ERROR);
|
||||
}
|
||||
|
||||
if (status == RET_SUCCESS) {
|
||||
__bt_setcur(t, e.page->pgno, 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(t, ep, key, flags)
|
||||
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(t, ep, flags)
|
||||
BTREE *t;
|
||||
EPG *ep;
|
||||
int flags;
|
||||
{
|
||||
CURSOR *c;
|
||||
PAGE *h;
|
||||
indx_t index;
|
||||
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;
|
||||
index = c->pg.index;
|
||||
if (++index == 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);
|
||||
index = 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);
|
||||
}
|
||||
index = c->pg.index;
|
||||
if (index == 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);
|
||||
index = NEXTINDEX(h) - 1;
|
||||
} else
|
||||
--index;
|
||||
break;
|
||||
}
|
||||
|
||||
ep->page = h;
|
||||
ep->index = index;
|
||||
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(t, key, erval, exactp)
|
||||
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 (RET_SPECIAL);
|
||||
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) {
|
||||
if (h->pgno == save.page->pgno)
|
||||
mpool_put(t->bt_mp,
|
||||
save.page, 0);
|
||||
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
|
||||
* index: page index
|
||||
*/
|
||||
void
|
||||
__bt_setcur(t, pgno, index)
|
||||
BTREE *t;
|
||||
pgno_t pgno;
|
||||
u_int index;
|
||||
{
|
||||
/* 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 = index;
|
||||
F_SET(&t->bt_cursor, CURS_INIT);
|
||||
}
|
||||
@@ -0,0 +1,827 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_split.c 8.9 (Berkeley) 7/26/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "btree.h"
|
||||
|
||||
static int bt_broot __P((BTREE *, PAGE *, PAGE *, PAGE *));
|
||||
static PAGE *bt_page
|
||||
__P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
|
||||
static int bt_preserve __P((BTREE *, pgno_t));
|
||||
static PAGE *bt_psplit
|
||||
__P((BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t));
|
||||
static PAGE *bt_root
|
||||
__P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
|
||||
static int bt_rroot __P((BTREE *, PAGE *, PAGE *, PAGE *));
|
||||
static recno_t rec_total __P((PAGE *));
|
||||
|
||||
#ifdef STATISTICS
|
||||
u_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(t, sp, key, data, flags, ilen, argskip)
|
||||
BTREE *t;
|
||||
PAGE *sp;
|
||||
const DBT *key, *data;
|
||||
int flags;
|
||||
size_t ilen;
|
||||
u_int32_t argskip;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BLEAF *bl, *tbl;
|
||||
DBT a, b;
|
||||
EPGNO *parent;
|
||||
PAGE *h, *l, *r, *lchild, *rchild;
|
||||
indx_t nxtindex;
|
||||
u_int16_t skip;
|
||||
u_int32_t n, nbytes, nksize;
|
||||
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.)
|
||||
*/
|
||||
h->linp[skip] = h->upper -= ilen;
|
||||
dest = (char *)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)) {
|
||||
tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
|
||||
a.size = tbl->ksize;
|
||||
a.data = tbl->bytes;
|
||||
b.size = bl->ksize;
|
||||
b.data = bl->bytes;
|
||||
nksize = t->bt_pfx(&a, &b);
|
||||
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 *)h + h->linp[skip];
|
||||
memmove(dest, bi, nbytes);
|
||||
((BINTERNAL *)dest)->pgno = rchild->pgno;
|
||||
break;
|
||||
case P_BLEAF:
|
||||
h->linp[skip] = h->upper -= nbytes;
|
||||
dest = (char *)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 *)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 *)h + h->linp[skip - 1];
|
||||
else
|
||||
dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
|
||||
((RINTERNAL *)dest)->nrecs = rec_total(lchild);
|
||||
((RINTERNAL *)dest)->pgno = lchild->pgno;
|
||||
|
||||
/* Update the right page count. */
|
||||
h->linp[skip] = h->upper -= nbytes;
|
||||
dest = (char *)h + h->linp[skip];
|
||||
((RINTERNAL *)dest)->nrecs = rec_total(rchild);
|
||||
((RINTERNAL *)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 *)h + h->linp[skip - 1];
|
||||
else
|
||||
dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
|
||||
((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
|
||||
((RINTERNAL *)dest)->pgno = lchild->pgno;
|
||||
|
||||
/* Update the right page count. */
|
||||
h->linp[skip] = h->upper -= nbytes;
|
||||
dest = (char *)h + h->linp[skip];
|
||||
((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
|
||||
((RINTERNAL *)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(t, h, lp, rp, skip, ilen)
|
||||
BTREE *t;
|
||||
PAGE *h, **lp, **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(t, h, lp, rp, skip, ilen)
|
||||
BTREE *t;
|
||||
PAGE *h, **lp, **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(t, h, l, r)
|
||||
BTREE *t;
|
||||
PAGE *h, *l, *r;
|
||||
{
|
||||
char *dest;
|
||||
|
||||
/* Insert the left and right keys, set the header information. */
|
||||
h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
|
||||
dest = (char *)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 *)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(t, h, l, r)
|
||||
BTREE *t;
|
||||
PAGE *h, *l, *r;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BLEAF *bl;
|
||||
u_int32_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 *)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 *)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 *)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 *)h + h->upper;
|
||||
memmove(dest, bi, nbytes);
|
||||
((BINTERNAL *)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(t, h, l, r, pskip, ilen)
|
||||
BTREE *t;
|
||||
PAGE *h, *l, *r;
|
||||
indx_t *pskip;
|
||||
size_t ilen;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BLEAF *bl;
|
||||
CURSOR *c;
|
||||
RLEAF *rl;
|
||||
PAGE *rval;
|
||||
void *src;
|
||||
indx_t full, half, nxt, off, skip, top, used;
|
||||
u_int32_t nbytes;
|
||||
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;
|
||||
full = t->bt_psize - BTDATAOFF;
|
||||
half = full / 2;
|
||||
used = 0;
|
||||
for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
|
||||
if (skip == off) {
|
||||
nbytes = 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 >= full) {
|
||||
--off;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy the key/data pair, if not the skipped index. */
|
||||
if (skip != off) {
|
||||
++nxt;
|
||||
|
||||
l->linp[off] = l->upper -= nbytes;
|
||||
memmove((char *)l + l->upper, src, nbytes);
|
||||
}
|
||||
|
||||
used += nbytes;
|
||||
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.
|
||||
*/
|
||||
l->lower += (off + 1) * sizeof(indx_t);
|
||||
|
||||
/*
|
||||
* 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 = 0;
|
||||
rval = l;
|
||||
} else {
|
||||
rval = r;
|
||||
*pskip -= nxt;
|
||||
}
|
||||
|
||||
for (off = 0; nxt < top; ++off) {
|
||||
if (skip == nxt) {
|
||||
++off;
|
||||
skip = 0;
|
||||
}
|
||||
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 *)r + r->upper, src, nbytes);
|
||||
}
|
||||
r->lower += off * sizeof(indx_t);
|
||||
|
||||
/* 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(t, pg)
|
||||
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(h)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)bt_utils.c 8.8 (Berkeley) 7/20/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <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(t, e, key, rkey, data, rdata, copy)
|
||||
BTREE *t;
|
||||
EPG *e;
|
||||
DBT *key, *rkey, *data, *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(t, k1, e)
|
||||
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(a, b)
|
||||
const DBT *a, *b;
|
||||
{
|
||||
register size_t len;
|
||||
register u_char *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(a, b)
|
||||
const DBT *a, *b;
|
||||
{
|
||||
register u_char *p1, *p2;
|
||||
register 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);
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)btree.h 8.11 (Berkeley) 8/17/94
|
||||
*/
|
||||
|
||||
/* 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 <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 */
|
||||
u_int32_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(u_int32_t) + sizeof(indx_t) + sizeof(indx_t))
|
||||
#define NEXTINDEX(p) (((p)->lower - BTDATAOFF) / sizeof(indx_t))
|
||||
|
||||
/*
|
||||
* 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 LALIGN(n) (((n) + sizeof(pgno_t) - 1) & ~(sizeof(pgno_t) - 1))
|
||||
#define NOVFLSIZE (sizeof(pgno_t) + sizeof(u_int32_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 {
|
||||
u_int32_t ksize; /* key size */
|
||||
pgno_t pgno; /* page number stored on */
|
||||
#define P_BIGDATA 0x01 /* overflow data */
|
||||
#define P_BIGKEY 0x02 /* overflow key */
|
||||
u_char flags;
|
||||
char bytes[1]; /* data */
|
||||
} BINTERNAL;
|
||||
|
||||
/* Get the page's BINTERNAL structure at index indx. */
|
||||
#define GETBINTERNAL(pg, indx) \
|
||||
((BINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
|
||||
|
||||
/* Get the number of bytes in the entry. */
|
||||
#define NBINTERNAL(len) \
|
||||
LALIGN(sizeof(u_int32_t) + sizeof(pgno_t) + sizeof(u_char) + (len))
|
||||
|
||||
/* Copy a BINTERNAL entry to the page. */
|
||||
#define WR_BINTERNAL(p, size, pgno, flags) { \
|
||||
*(u_int32_t *)p = size; \
|
||||
p += sizeof(u_int32_t); \
|
||||
*(pgno_t *)p = pgno; \
|
||||
p += sizeof(pgno_t); \
|
||||
*(u_char *)p = flags; \
|
||||
p += sizeof(u_char); \
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *)((char *)(pg) + (pg)->linp[indx]))
|
||||
|
||||
/* Get the number of bytes in the entry. */
|
||||
#define NRINTERNAL \
|
||||
LALIGN(sizeof(recno_t) + sizeof(pgno_t))
|
||||
|
||||
/* Copy a RINTERAL entry to the page. */
|
||||
#define WR_RINTERNAL(p, nrecs, pgno) { \
|
||||
*(recno_t *)p = nrecs; \
|
||||
p += sizeof(recno_t); \
|
||||
*(pgno_t *)p = pgno; \
|
||||
}
|
||||
|
||||
/* For the btree leaf pages, the item is a key and data pair. */
|
||||
typedef struct _bleaf {
|
||||
u_int32_t ksize; /* size of key */
|
||||
u_int32_t dsize; /* size of data */
|
||||
u_char flags; /* P_BIGDATA, P_BIGKEY */
|
||||
char bytes[1]; /* data */
|
||||
} BLEAF;
|
||||
|
||||
/* Get the page's BLEAF structure at index indx. */
|
||||
#define GETBLEAF(pg, indx) \
|
||||
((BLEAF *)((char *)(pg) + (pg)->linp[indx]))
|
||||
|
||||
/* Get the number of bytes in the entry. */
|
||||
#define NBLEAF(p) NBLEAFDBT((p)->ksize, (p)->dsize)
|
||||
|
||||
/* Get the number of bytes in the user's key/data pair. */
|
||||
#define NBLEAFDBT(ksize, dsize) \
|
||||
LALIGN(sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(u_char) + \
|
||||
(ksize) + (dsize))
|
||||
|
||||
/* Copy a BLEAF entry to the page. */
|
||||
#define WR_BLEAF(p, key, data, flags) { \
|
||||
*(u_int32_t *)p = key->size; \
|
||||
p += sizeof(u_int32_t); \
|
||||
*(u_int32_t *)p = data->size; \
|
||||
p += sizeof(u_int32_t); \
|
||||
*(u_char *)p = flags; \
|
||||
p += sizeof(u_char); \
|
||||
memmove(p, key->data, key->size); \
|
||||
p += key->size; \
|
||||
memmove(p, data->data, data->size); \
|
||||
}
|
||||
|
||||
/* For the recno leaf pages, the item is a data entry. */
|
||||
typedef struct _rleaf {
|
||||
u_int32_t dsize; /* size of data */
|
||||
u_char flags; /* P_BIGDATA */
|
||||
char bytes[1];
|
||||
} RLEAF;
|
||||
|
||||
/* Get the page's RLEAF structure at index indx. */
|
||||
#define GETRLEAF(pg, indx) \
|
||||
((RLEAF *)((char *)(pg) + (pg)->linp[indx]))
|
||||
|
||||
/* Get the number of bytes in the entry. */
|
||||
#define NRLEAF(p) NRLEAFDBT((p)->dsize)
|
||||
|
||||
/* Get the number of bytes from the user's data. */
|
||||
#define NRLEAFDBT(dsize) \
|
||||
LALIGN(sizeof(u_int32_t) + sizeof(u_char) + (dsize))
|
||||
|
||||
/* Copy a RLEAF entry to the page. */
|
||||
#define WR_RLEAF(p, data, flags) { \
|
||||
*(u_int32_t *)p = data->size; \
|
||||
p += sizeof(u_int32_t); \
|
||||
*(u_char *)p = flags; \
|
||||
p += sizeof(u_char); \
|
||||
memmove(p, data->data, data->size); \
|
||||
}
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
u_int8_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 {
|
||||
u_int32_t magic; /* magic number */
|
||||
u_int32_t version; /* version */
|
||||
u_int32_t psize; /* page size */
|
||||
u_int32_t free; /* page number of first free page */
|
||||
u_int32_t nrecs; /* R: number of records */
|
||||
|
||||
#define SAVEMETA (B_NODUPS | R_RECNO)
|
||||
u_int32_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 */
|
||||
u_int32_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) __P((const DBT *, const DBT *));
|
||||
/* B: prefix comparison function */
|
||||
size_t (*bt_pfx) __P((const DBT *, const DBT *));
|
||||
/* R: recno input function */
|
||||
int (*bt_irec) __P((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 */
|
||||
u_char 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. */
|
||||
u_int32_t flags;
|
||||
} BTREE;
|
||||
|
||||
#include "extern.h"
|
||||
@@ -0,0 +1,70 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.10 (Berkeley) 7/20/94
|
||||
*/
|
||||
|
||||
int __bt_close __P((DB *));
|
||||
int __bt_cmp __P((BTREE *, const DBT *, EPG *));
|
||||
int __bt_crsrdel __P((BTREE *, EPGNO *));
|
||||
int __bt_defcmp __P((const DBT *, const DBT *));
|
||||
size_t __bt_defpfx __P((const DBT *, const DBT *));
|
||||
int __bt_delete __P((const DB *, const DBT *, u_int));
|
||||
int __bt_dleaf __P((BTREE *, const DBT *, PAGE *, u_int));
|
||||
int __bt_fd __P((const DB *));
|
||||
int __bt_free __P((BTREE *, PAGE *));
|
||||
int __bt_get __P((const DB *, const DBT *, DBT *, u_int));
|
||||
PAGE *__bt_new __P((BTREE *, pgno_t *));
|
||||
void __bt_pgin __P((void *, pgno_t, void *));
|
||||
void __bt_pgout __P((void *, pgno_t, void *));
|
||||
int __bt_push __P((BTREE *, pgno_t, int));
|
||||
int __bt_put __P((const DB *dbp, DBT *, const DBT *, u_int));
|
||||
int __bt_ret __P((BTREE *, EPG *, DBT *, DBT *, DBT *, DBT *, int));
|
||||
EPG *__bt_search __P((BTREE *, const DBT *, int *));
|
||||
int __bt_seq __P((const DB *, DBT *, DBT *, u_int));
|
||||
void __bt_setcur __P((BTREE *, pgno_t, u_int));
|
||||
int __bt_split __P((BTREE *, PAGE *,
|
||||
const DBT *, const DBT *, int, size_t, u_int32_t));
|
||||
int __bt_sync __P((const DB *, u_int));
|
||||
|
||||
int __ovfl_delete __P((BTREE *, void *));
|
||||
int __ovfl_get __P((BTREE *, void *, size_t *, void **, size_t *));
|
||||
int __ovfl_put __P((BTREE *, const DBT *, pgno_t *));
|
||||
|
||||
#ifdef DEBUG
|
||||
void __bt_dnpage __P((DB *, pgno_t));
|
||||
void __bt_dpage __P((PAGE *));
|
||||
void __bt_dump __P((DB *));
|
||||
#endif
|
||||
#ifdef STATISTICS
|
||||
void __bt_stat __P((DB *));
|
||||
#endif
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/* Values for building 4.4 BSD db routines in the GNU C library. */
|
||||
|
||||
#ifndef _compat_h_
|
||||
#define _compat_h_
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
* If you can't provide lock values in the open(2) call. Note, this
|
||||
* allows races to happen.
|
||||
*/
|
||||
#ifndef O_EXLOCK /* 4.4BSD extension. */
|
||||
#define O_EXLOCK 0
|
||||
#endif
|
||||
|
||||
#ifndef O_SHLOCK /* 4.4BSD extension. */
|
||||
#define O_SHLOCK 0
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef EFTYPE
|
||||
#define EFTYPE EINVAL /* POSIX 1003.1 format errno. */
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef _POSIX_VDISABLE /* POSIX 1003.1 disabling char. */
|
||||
#define _POSIX_VDISABLE 0 /* Some systems used 0. */
|
||||
#endif
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
#ifndef TCSASOFT /* 4.4BSD extension. */
|
||||
#define TCSASOFT 0
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifndef MAX /* Usually found in <sys/param.h>. */
|
||||
#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a))
|
||||
#endif
|
||||
#ifndef MIN /* Usually found in <sys/param.h>. */
|
||||
#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* compat.h */
|
||||
@@ -0,0 +1,236 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)db.h 8.7 (Berkeley) 6/16/94
|
||||
*/
|
||||
|
||||
#ifndef _DB_H_
|
||||
#define _DB_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __DBINTERFACE_PRIVATE
|
||||
#include <compat.h>
|
||||
#endif
|
||||
|
||||
#define RET_ERROR -1 /* Return values. */
|
||||
#define RET_SUCCESS 0
|
||||
#define RET_SPECIAL 1
|
||||
|
||||
#ifndef __BIT_TYPES_DEFINED__
|
||||
#define __BIT_TYPES_DEFINED__
|
||||
typedef __signed char int8_t;
|
||||
typedef unsigned char u_int8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short u_int16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int u_int32_t;
|
||||
#ifdef WE_DONT_NEED_QUADS
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long u_int64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */
|
||||
typedef u_int32_t pgno_t;
|
||||
#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */
|
||||
typedef u_int16_t indx_t;
|
||||
#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */
|
||||
typedef u_int32_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) __P((struct __db *));
|
||||
int (*del) __P((const struct __db *, const DBT *, u_int));
|
||||
int (*get) __P((const struct __db *, const DBT *, DBT *, u_int));
|
||||
int (*put) __P((const struct __db *, DBT *, const DBT *, u_int));
|
||||
int (*seq) __P((const struct __db *, DBT *, DBT *, u_int));
|
||||
int (*sync) __P((const struct __db *, u_int));
|
||||
void *internal; /* Access method private. */
|
||||
int (*fd) __P((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 */
|
||||
u_long flags;
|
||||
u_int cachesize; /* bytes to cache */
|
||||
int maxkeypage; /* maximum keys per page */
|
||||
int minkeypage; /* minimum keys per page */
|
||||
u_int psize; /* page size */
|
||||
int (*compare) /* comparison function */
|
||||
__P((const DBT *, const DBT *));
|
||||
size_t (*prefix) /* prefix function */
|
||||
__P((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 {
|
||||
u_int bsize; /* bucket size */
|
||||
u_int ffactor; /* fill factor */
|
||||
u_int nelem; /* number of elements */
|
||||
u_int cachesize; /* bytes to cache */
|
||||
u_int32_t /* hash function */
|
||||
(*hash) __P((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 */
|
||||
u_long flags;
|
||||
u_int cachesize; /* bytes to cache */
|
||||
u_int psize; /* page size */
|
||||
int lorder; /* byte order */
|
||||
size_t reclen; /* record length (fixed-length records) */
|
||||
u_char 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) { \
|
||||
u_int32_t _tmp = a; \
|
||||
((char *)&a)[0] = ((char *)&_tmp)[3]; \
|
||||
((char *)&a)[1] = ((char *)&_tmp)[2]; \
|
||||
((char *)&a)[2] = ((char *)&_tmp)[1]; \
|
||||
((char *)&a)[3] = ((char *)&_tmp)[0]; \
|
||||
}
|
||||
#define P_32_SWAP(a) { \
|
||||
u_int32_t _tmp = *(u_int32_t *)a; \
|
||||
((char *)a)[0] = ((char *)&_tmp)[3]; \
|
||||
((char *)a)[1] = ((char *)&_tmp)[2]; \
|
||||
((char *)a)[2] = ((char *)&_tmp)[1]; \
|
||||
((char *)a)[3] = ((char *)&_tmp)[0]; \
|
||||
}
|
||||
#define P_32_COPY(a, b) { \
|
||||
((char *)&(b))[0] = ((char *)&(a))[3]; \
|
||||
((char *)&(b))[1] = ((char *)&(a))[2]; \
|
||||
((char *)&(b))[2] = ((char *)&(a))[1]; \
|
||||
((char *)&(b))[3] = ((char *)&(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) { \
|
||||
u_int16_t _tmp = a; \
|
||||
((char *)&a)[0] = ((char *)&_tmp)[1]; \
|
||||
((char *)&a)[1] = ((char *)&_tmp)[0]; \
|
||||
}
|
||||
#define P_16_SWAP(a) { \
|
||||
u_int16_t _tmp = *(u_int16_t *)a; \
|
||||
((char *)a)[0] = ((char *)&_tmp)[1]; \
|
||||
((char *)a)[1] = ((char *)&_tmp)[0]; \
|
||||
}
|
||||
#define P_16_COPY(a, b) { \
|
||||
((char *)&(b))[0] = ((char *)&(a))[1]; \
|
||||
((char *)&(b))[1] = ((char *)&(a))[0]; \
|
||||
}
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
|
||||
|
||||
#ifdef __DBINTERFACE_PRIVATE
|
||||
DB *__bt_open __P((const char *, int, int, const BTREEINFO *, int));
|
||||
DB *__hash_open __P((const char *, int, int, const HASHINFO *, int));
|
||||
DB *__rec_open __P((const char *, int, int, const RECNOINFO *, int));
|
||||
void __dbpanic __P((DB *dbp));
|
||||
#endif
|
||||
__END_DECLS
|
||||
#endif /* !_DB_H_ */
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)db.c 8.4 (Berkeley) 2/21/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <db.h>
|
||||
|
||||
DB *
|
||||
dbopen(fname, flags, mode, type, openinfo)
|
||||
const char *fname;
|
||||
int flags, mode;
|
||||
DBTYPE type;
|
||||
const void *openinfo;
|
||||
{
|
||||
|
||||
#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, flags & DB_FLAGS));
|
||||
case DB_HASH:
|
||||
return (__hash_open(fname, flags & USE_OPEN_FLAGS,
|
||||
mode, openinfo, flags & DB_FLAGS));
|
||||
case DB_RECNO:
|
||||
return (__rec_open(fname, flags & USE_OPEN_FLAGS,
|
||||
mode, openinfo, flags & DB_FLAGS));
|
||||
}
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
__dberr __P((void))
|
||||
{
|
||||
return (RET_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* __DBPANIC -- Stop.
|
||||
*
|
||||
* Parameters:
|
||||
* dbp: pointer to the DB structure.
|
||||
*/
|
||||
void
|
||||
__dbpanic(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
/* The only thing that can succeed is a close. */
|
||||
dbp->del = (int (*)__P((const struct __db *,
|
||||
const DBT *, u_int))) __dberr;
|
||||
dbp->get = (int (*)__P((const struct __db *,
|
||||
const DBT *, DBT *, u_int))) __dberr;
|
||||
dbp->put = (int (*)__P((const struct __db *,
|
||||
DBT *, const DBT *, u_int))) __dberr;
|
||||
dbp->seq = (int (*)__P((const struct __db *,
|
||||
DBT *, DBT *, u_int))) __dberr;
|
||||
dbp->sync = (int (*)__P((const struct __db *, u_int))) __dberr;
|
||||
dbp->fd = (int (*)__P((const struct __db *))) __dberr;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.4 (Berkeley) 6/16/94
|
||||
*/
|
||||
|
||||
BUFHEAD *__add_ovflpage __P((HTAB *, BUFHEAD *));
|
||||
int __addel __P((HTAB *, BUFHEAD *, const DBT *, const DBT *));
|
||||
int __big_delete __P((HTAB *, BUFHEAD *));
|
||||
int __big_insert __P((HTAB *, BUFHEAD *, const DBT *, const DBT *));
|
||||
int __big_keydata __P((HTAB *, BUFHEAD *, DBT *, DBT *, int));
|
||||
int __big_return __P((HTAB *, BUFHEAD *, int, DBT *, int));
|
||||
int __big_split __P((HTAB *, BUFHEAD *, BUFHEAD *, BUFHEAD *,
|
||||
int, u_int32_t, SPLIT_RETURN *));
|
||||
int __buf_free __P((HTAB *, int, int));
|
||||
void __buf_init __P((HTAB *, int));
|
||||
u_int32_t __call_hash __P((HTAB *, char *, int));
|
||||
int __delpair __P((HTAB *, BUFHEAD *, int));
|
||||
int __expand_table __P((HTAB *));
|
||||
int __find_bigpair __P((HTAB *, BUFHEAD *, int, char *, int));
|
||||
u_int16_t __find_last_page __P((HTAB *, BUFHEAD **));
|
||||
void __free_ovflpage __P((HTAB *, BUFHEAD *));
|
||||
BUFHEAD *__get_buf __P((HTAB *, u_int32_t, BUFHEAD *, int));
|
||||
int __get_page __P((HTAB *, char *, u_int32_t, int, int, int));
|
||||
int __ibitmap __P((HTAB *, int, int, int));
|
||||
u_int32_t __log2 __P((u_int32_t));
|
||||
int __put_page __P((HTAB *, char *, u_int32_t, int, int));
|
||||
void __reclaim_buf __P((HTAB *, BUFHEAD *));
|
||||
int __split_page __P((HTAB *, u_int32_t, u_int32_t));
|
||||
|
||||
/* Default hash routine. */
|
||||
extern u_int32_t (*__default_hash) __P((const void *, size_t));
|
||||
|
||||
#ifdef HASH_STATISTICS
|
||||
extern int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
|
||||
#endif
|
||||
+994
@@ -0,0 +1,994 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash.c 8.9 (Berkeley) 6/16/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <db.h>
|
||||
#include "hash.h"
|
||||
#include "page.h"
|
||||
#include "extern.h"
|
||||
|
||||
static int alloc_segs __P((HTAB *, int));
|
||||
static int flush_meta __P((HTAB *));
|
||||
static int hash_access __P((HTAB *, ACTION, DBT *, DBT *));
|
||||
static int hash_close __P((DB *));
|
||||
static int hash_delete __P((const DB *, const DBT *, u_int32_t));
|
||||
static int hash_fd __P((const DB *));
|
||||
static int hash_get __P((const DB *, const DBT *, DBT *, u_int32_t));
|
||||
static int hash_put __P((const DB *, DBT *, const DBT *, u_int32_t));
|
||||
static void *hash_realloc __P((SEGMENT **, int, int));
|
||||
static int hash_seq __P((const DB *, DBT *, DBT *, u_int32_t));
|
||||
static int hash_sync __P((const DB *, u_int32_t));
|
||||
static int hdestroy __P((HTAB *));
|
||||
static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));
|
||||
static int init_htab __P((HTAB *, int));
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
static void swap_header __P((HTAB *));
|
||||
static void swap_header_copy __P((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 */
|
||||
|
||||
extern DB *
|
||||
__hash_open(file, flags, mode, info, dflags)
|
||||
const char *file;
|
||||
int flags, mode, dflags;
|
||||
const HASHINFO *info; /* Special directives for create */
|
||||
{
|
||||
HTAB *hashp;
|
||||
struct stat statbuf;
|
||||
DB *dbp;
|
||||
int bpages, hdrsize, new_table, nsegs, save_errno;
|
||||
|
||||
if ((flags & O_ACCMODE) == O_WRONLY) {
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!(hashp = (HTAB *)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);
|
||||
(void)fcntl(hashp->fp, F_SETFD, 1);
|
||||
}
|
||||
if (new_table) {
|
||||
if (!(hashp = init_hash(hashp, file, (HASHINFO *)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] +
|
||||
(hashp->BSIZE << BYTE_SHIFT) - 1) >>
|
||||
(hashp->BSHIFT + BYTE_SHIFT);
|
||||
|
||||
hashp->nmaps = bpages;
|
||||
(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_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 = (DB *)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%x\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(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
HTAB *hashp;
|
||||
int retval;
|
||||
|
||||
if (!dbp)
|
||||
return (ERROR);
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
retval = hdestroy(hashp);
|
||||
free(dbp);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_fd(dbp)
|
||||
const DB *dbp;
|
||||
{
|
||||
HTAB *hashp;
|
||||
|
||||
if (!dbp)
|
||||
return (ERROR);
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
if (hashp->fp == -1) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
return (hashp->fp);
|
||||
}
|
||||
|
||||
/************************** LOCAL CREATION ROUTINES **********************/
|
||||
static HTAB *
|
||||
init_hash(hashp, file, info)
|
||||
HTAB *hashp;
|
||||
const char *file;
|
||||
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 = statbuf.st_blksize;
|
||||
hashp->BSHIFT = __log2(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, 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(hashp, nelem)
|
||||
HTAB *hashp;
|
||||
int nelem;
|
||||
{
|
||||
register int nbuckets, 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;
|
||||
|
||||
l2 = __log2(MAX(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, OADDR_OF(l2, 1), l2 + 1, 0))
|
||||
return (-1);
|
||||
|
||||
hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
|
||||
hashp->HIGH_MASK = (nbuckets << 1) - 1;
|
||||
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, nsegs));
|
||||
}
|
||||
|
||||
/********************** DESTROY/CLOSE ROUTINES ************************/
|
||||
|
||||
/*
|
||||
* Flushes any changes to the file if necessary and destroys the hashp
|
||||
* structure, freeing all allocated space.
|
||||
*/
|
||||
static int
|
||||
hdestroy(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
int i, save_errno;
|
||||
|
||||
save_errno = 0;
|
||||
|
||||
#ifdef HASH_STATISTICS
|
||||
(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
|
||||
hash_accesses, hash_collisions);
|
||||
(void)fprintf(stderr, "hdestroy: expansions %ld\n",
|
||||
hash_expansions);
|
||||
(void)fprintf(stderr, "hdestroy: overflows %ld\n",
|
||||
hash_overflows);
|
||||
(void)fprintf(stderr, "keys %ld 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(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
HTAB *hashp;
|
||||
|
||||
if (flags != 0) {
|
||||
errno = EINVAL;
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
if (!dbp)
|
||||
return (ERROR);
|
||||
|
||||
hashp = (HTAB *)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(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
HASHHDR *whdrp;
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
HASHHDR whdr;
|
||||
#endif
|
||||
int fp, i, 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 ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
|
||||
((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
|
||||
return (-1);
|
||||
else
|
||||
if (wsize != sizeof(HASHHDR)) {
|
||||
errno = EFTYPE;
|
||||
hashp->errno = errno;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < NCACHED; i++)
|
||||
if (hashp->mapp[i])
|
||||
if (__put_page(hashp, (char *)hashp->mapp[i],
|
||||
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(dbp, key, data, flag)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flag;
|
||||
{
|
||||
HTAB *hashp;
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
if (flag) {
|
||||
hashp->errno = errno = EINVAL;
|
||||
return (ERROR);
|
||||
}
|
||||
return (hash_access(hashp, HASH_GET, (DBT *)key, data));
|
||||
}
|
||||
|
||||
static int
|
||||
hash_put(dbp, key, data, flag)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
const DBT *data;
|
||||
u_int32_t flag;
|
||||
{
|
||||
HTAB *hashp;
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
if (flag && flag != R_NOOVERWRITE) {
|
||||
hashp->errno = errno = EINVAL;
|
||||
return (ERROR);
|
||||
}
|
||||
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
|
||||
hashp->errno = errno = EPERM;
|
||||
return (ERROR);
|
||||
}
|
||||
return (hash_access(hashp, flag == R_NOOVERWRITE ?
|
||||
HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
|
||||
}
|
||||
|
||||
static int
|
||||
hash_delete(dbp, key, flag)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
u_int32_t flag; /* Ignored */
|
||||
{
|
||||
HTAB *hashp;
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
if (flag && flag != R_CURSOR) {
|
||||
hashp->errno = errno = EINVAL;
|
||||
return (ERROR);
|
||||
}
|
||||
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
|
||||
hashp->errno = errno = EPERM;
|
||||
return (ERROR);
|
||||
}
|
||||
return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that hashp has been set in wrapper routine.
|
||||
*/
|
||||
static int
|
||||
hash_access(hashp, action, key, val)
|
||||
HTAB *hashp;
|
||||
ACTION action;
|
||||
DBT *key, *val;
|
||||
{
|
||||
register BUFHEAD *rbufp;
|
||||
BUFHEAD *bufp, *save_bufp;
|
||||
register u_int16_t *bp;
|
||||
register int n, ndx, off, size;
|
||||
register char *kp;
|
||||
u_int16_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, size), NULL, 0);
|
||||
if (!rbufp)
|
||||
return (ERROR);
|
||||
save_bufp = rbufp;
|
||||
|
||||
/* Pin the bucket chain */
|
||||
rbufp->flags |= BUF_PIN;
|
||||
for (bp = (u_int16_t *)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, *bp, rbufp, 0);
|
||||
if (!rbufp) {
|
||||
save_bufp->flags &= ~BUF_PIN;
|
||||
return (ERROR);
|
||||
}
|
||||
/* FOR LOOP INIT */
|
||||
bp = (u_int16_t *)rbufp->page;
|
||||
n = *bp++;
|
||||
ndx = 1;
|
||||
off = hashp->BSIZE;
|
||||
} else if (bp[1] < REAL_KEY) {
|
||||
if ((ndx =
|
||||
__find_bigpair(hashp, rbufp, ndx, kp, 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, pageno, bufp, 0);
|
||||
if (!rbufp) {
|
||||
save_bufp->flags &= ~BUF_PIN;
|
||||
return (ERROR);
|
||||
}
|
||||
/* FOR LOOP INIT */
|
||||
bp = (u_int16_t *)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 = (u_int16_t *)rbufp->page;
|
||||
if (bp[ndx + 1] < REAL_KEY) {
|
||||
if (__big_return(hashp, rbufp, ndx, val, 0))
|
||||
return (ERROR);
|
||||
} else {
|
||||
val->data = (u_char *)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(dbp, key, data, flag)
|
||||
const DB *dbp;
|
||||
DBT *key, *data;
|
||||
u_int32_t flag;
|
||||
{
|
||||
register u_int32_t bucket;
|
||||
register BUFHEAD *bufp;
|
||||
HTAB *hashp;
|
||||
u_int16_t *bp, ndx;
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
if (flag && flag != R_FIRST && flag != R_NEXT) {
|
||||
hashp->errno = 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 = (u_int16_t *)bufp->page;
|
||||
if (bp[0])
|
||||
break;
|
||||
}
|
||||
hashp->cbucket = bucket;
|
||||
if (hashp->cbucket > hashp->MAX_BUCKET) {
|
||||
hashp->cbucket = -1;
|
||||
return (ABNORMAL);
|
||||
}
|
||||
} else
|
||||
bp = (u_int16_t *)hashp->cpage->page;
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(bp);
|
||||
assert(bufp);
|
||||
#endif
|
||||
while (bp[hashp->cndx + 1] == OVFLPAGE) {
|
||||
bufp = hashp->cpage =
|
||||
__get_buf(hashp, bp[hashp->cndx], bufp, 0);
|
||||
if (!bufp)
|
||||
return (ERROR);
|
||||
bp = (u_int16_t *)(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 {
|
||||
key->data = (u_char *)hashp->cpage->page + bp[ndx];
|
||||
key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
|
||||
data->data = (u_char *)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
|
||||
*/
|
||||
extern int
|
||||
__expand_table(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
u_int32_t old_bucket, new_bucket;
|
||||
int dirsize, new_segnum, spare_ndx;
|
||||
|
||||
#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] =
|
||||
(SEGMENT)calloc(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(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(p_ptr, oldsize, newsize)
|
||||
SEGMENT **p_ptr;
|
||||
int oldsize, newsize;
|
||||
{
|
||||
register void *p;
|
||||
|
||||
if (p = malloc(newsize)) {
|
||||
memmove(p, *p_ptr, oldsize);
|
||||
memset((char *)p + oldsize, 0, newsize - oldsize);
|
||||
free(*p_ptr);
|
||||
*p_ptr = p;
|
||||
}
|
||||
return (p);
|
||||
}
|
||||
|
||||
extern u_int32_t
|
||||
__call_hash(hashp, k, len)
|
||||
HTAB *hashp;
|
||||
char *k;
|
||||
int len;
|
||||
{
|
||||
int n, bucket;
|
||||
|
||||
n = hashp->hash(k, 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(hashp, nsegs)
|
||||
HTAB *hashp;
|
||||
int nsegs;
|
||||
{
|
||||
register int i;
|
||||
register SEGMENT store;
|
||||
|
||||
int save_errno;
|
||||
|
||||
if ((hashp->dir =
|
||||
(SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
|
||||
save_errno = errno;
|
||||
(void)hdestroy(hashp);
|
||||
errno = save_errno;
|
||||
return (-1);
|
||||
}
|
||||
/* Allocate segments */
|
||||
if ((store =
|
||||
(SEGMENT)calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
|
||||
save_errno = errno;
|
||||
(void)hdestroy(hashp);
|
||||
errno = save_errno;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < nsegs; i++, hashp->nsegs++)
|
||||
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(srcp, destp)
|
||||
HASHHDR *srcp, *destp;
|
||||
{
|
||||
int 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(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
HASHHDR *hdrp;
|
||||
int 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
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)hash.h 8.3 (Berkeley) 5/31/94
|
||||
*/
|
||||
|
||||
/* 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 */
|
||||
u_int32_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 */
|
||||
int magic; /* Magic NO for hash tables */
|
||||
int version; /* Version ID */
|
||||
u_int32_t lorder; /* Byte Order */
|
||||
int bsize; /* Bucket/Page Size */
|
||||
int bshift; /* Bucket shift */
|
||||
int dsize; /* Directory Size */
|
||||
int ssize; /* Segment Size */
|
||||
int sshift; /* Segment shift */
|
||||
int ovfl_point; /* Where overflow pages are being
|
||||
* allocated */
|
||||
int last_freed; /* Last overflow page freed */
|
||||
int max_bucket; /* ID of Maximum bucket in use */
|
||||
int high_mask; /* Mask to modulo into entire table */
|
||||
int low_mask; /* Mask to modulo into lower half of
|
||||
* table */
|
||||
int ffactor; /* Fill factor */
|
||||
int nkeys; /* Number of keys in hash table */
|
||||
int hdrpages; /* Size of table header */
|
||||
int h_charkey; /* value of hash(CHARKEY) */
|
||||
#define NCACHED 32 /* number of bit maps and spare
|
||||
* points */
|
||||
int spares[NCACHED];/* spare pages for overflow */
|
||||
u_int16_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 */
|
||||
u_int32_t /* Hash function */
|
||||
(*hash)__P((const void *, size_t));
|
||||
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 errno; /* Error Number -- for DBM
|
||||
* compatability */
|
||||
int new_file; /* Indicates if fd is backing store
|
||||
* or no */
|
||||
int save_file; /* Indicates whether we need to flush
|
||||
* file at
|
||||
* exit */
|
||||
u_int32_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 ((u_int32_t)0xFFFFFFFF)
|
||||
#define ALL_CLEAR 0
|
||||
|
||||
#define PTROF(X) ((BUFHEAD *)((ptrdiff_t)(X)&~0x3))
|
||||
#define ISMOD(X) ((u_int32_t)(ptrdiff_t)(X)&0x1)
|
||||
#define DOMOD(X) ((X) = (char *)((ptrdiff_t)(X)|0x1))
|
||||
#define ISDISK(X) ((u_int32_t)(ptrdiff_t)(X)&0x2)
|
||||
#define DODISK(X) ((X) = (char *)((ptrdiff_t)(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) (((u_int32_t)(N)) >> SPLITSHIFT)
|
||||
#define OPAGENUM(N) ((N) & SPLITMASK)
|
||||
#define OADDR_OF(S,O) ((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
|
||||
|
||||
#define BUCKET_TO_PAGE(B) \
|
||||
(B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__log2((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 */
|
||||
#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
|
||||
@@ -0,0 +1,667 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash_bigkey.c 8.3 (Berkeley) 5/31/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <db.h>
|
||||
#include "hash.h"
|
||||
#include "page.h"
|
||||
#include "extern.h"
|
||||
|
||||
static int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int));
|
||||
static int collect_data __P((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
|
||||
*/
|
||||
extern int
|
||||
__big_insert(hashp, bufp, key, val)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
const DBT *key, *val;
|
||||
{
|
||||
register u_int16_t *p;
|
||||
int key_size, n, val_size;
|
||||
u_int16_t space, move_bytes, off;
|
||||
char *cp, *key_data, *val_data;
|
||||
|
||||
cp = bufp->page; /* Character pointer of p. */
|
||||
p = (u_int16_t *)cp;
|
||||
|
||||
key_data = (char *)key->data;
|
||||
key_size = key->size;
|
||||
val_data = (char *)val->data;
|
||||
val_size = val->size;
|
||||
|
||||
/* First move the Key */
|
||||
for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
|
||||
space = FREESPACE(p) - BIGOVERHEAD) {
|
||||
move_bytes = MIN(space, key_size);
|
||||
off = OFFSET(p) - move_bytes;
|
||||
memmove(cp + off, key_data, move_bytes);
|
||||
key_size -= move_bytes;
|
||||
key_data += move_bytes;
|
||||
n = p[0];
|
||||
p[++n] = off;
|
||||
p[0] = ++n;
|
||||
FREESPACE(p) = off - PAGE_META(n);
|
||||
OFFSET(p) = off;
|
||||
p[n] = PARTIAL_KEY;
|
||||
bufp = __add_ovflpage(hashp, bufp);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
n = p[0];
|
||||
if (!key_size)
|
||||
if (FREESPACE(p)) {
|
||||
move_bytes = MIN(FREESPACE(p), val_size);
|
||||
off = OFFSET(p) - move_bytes;
|
||||
p[n] = off;
|
||||
memmove(cp + off, val_data, move_bytes);
|
||||
val_data += move_bytes;
|
||||
val_size -= move_bytes;
|
||||
p[n - 2] = FULL_KEY_DATA;
|
||||
FREESPACE(p) = FREESPACE(p) - move_bytes;
|
||||
OFFSET(p) = off;
|
||||
} else
|
||||
p[n - 2] = FULL_KEY;
|
||||
p = (u_int16_t *)bufp->page;
|
||||
cp = bufp->page;
|
||||
bufp->flags |= BUF_MOD;
|
||||
}
|
||||
|
||||
/* Now move the data */
|
||||
for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
|
||||
space = FREESPACE(p) - BIGOVERHEAD) {
|
||||
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, move_bytes);
|
||||
val_size -= move_bytes;
|
||||
val_data += move_bytes;
|
||||
n = p[0];
|
||||
p[++n] = off;
|
||||
p[0] = ++n;
|
||||
FREESPACE(p) = off - PAGE_META(n);
|
||||
OFFSET(p) = off;
|
||||
if (val_size) {
|
||||
p[n] = FULL_KEY;
|
||||
bufp = __add_ovflpage(hashp, bufp);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
cp = bufp->page;
|
||||
p = (u_int16_t *)cp;
|
||||
} else
|
||||
p[n] = FULL_KEY_DATA;
|
||||
bufp->flags |= BUF_MOD;
|
||||
}
|
||||
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
|
||||
*/
|
||||
extern int
|
||||
__big_delete(hashp, bufp)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
{
|
||||
register BUFHEAD *last_bfp, *rbufp;
|
||||
u_int16_t *bp, pageno;
|
||||
int key_done, n;
|
||||
|
||||
rbufp = bufp;
|
||||
last_bfp = NULL;
|
||||
bp = (u_int16_t *)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, pageno, rbufp, 0);
|
||||
if (last_bfp)
|
||||
__free_ovflpage(hashp, last_bfp);
|
||||
last_bfp = rbufp;
|
||||
if (!rbufp)
|
||||
return (-1); /* Error. */
|
||||
bp = (u_int16_t *)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 = (u_int16_t *)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;
|
||||
FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
|
||||
OFFSET(bp) = hashp->BSIZE - 1;
|
||||
|
||||
bufp->flags |= BUF_MOD;
|
||||
if (rbufp)
|
||||
__free_ovflpage(hashp, rbufp);
|
||||
if (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
|
||||
*/
|
||||
extern int
|
||||
__find_bigpair(hashp, bufp, ndx, key, size)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
int ndx;
|
||||
char *key;
|
||||
int size;
|
||||
{
|
||||
register u_int16_t *bp;
|
||||
register char *p;
|
||||
int ksize;
|
||||
u_int16_t bytes;
|
||||
char *kkey;
|
||||
|
||||
bp = (u_int16_t *)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, bytes))
|
||||
return (-2);
|
||||
kkey += bytes;
|
||||
ksize -= bytes;
|
||||
bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-3);
|
||||
p = bufp->page;
|
||||
bp = (u_int16_t *)p;
|
||||
ndx = 1;
|
||||
}
|
||||
|
||||
if (bytes != ksize || memcmp(p + bp[ndx], kkey, 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)
|
||||
*/
|
||||
extern u_int16_t
|
||||
__find_last_page(hashp, bpp)
|
||||
HTAB *hashp;
|
||||
BUFHEAD **bpp;
|
||||
{
|
||||
BUFHEAD *bufp;
|
||||
u_int16_t *bp, pageno;
|
||||
int n;
|
||||
|
||||
bufp = *bpp;
|
||||
bp = (u_int16_t *)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, pageno, bufp, 0);
|
||||
if (!bufp)
|
||||
return (0); /* Need to indicate an error! */
|
||||
bp = (u_int16_t *)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).
|
||||
*/
|
||||
extern int
|
||||
__big_return(hashp, bufp, ndx, val, set_current)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
int ndx;
|
||||
DBT *val;
|
||||
int set_current;
|
||||
{
|
||||
BUFHEAD *save_p;
|
||||
u_int16_t *bp, len, off, save_addr;
|
||||
char *tp;
|
||||
|
||||
bp = (u_int16_t *)bufp->page;
|
||||
while (bp[ndx + 1] == PARTIAL_KEY) {
|
||||
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
bp = (u_int16_t *)bufp->page;
|
||||
ndx = 1;
|
||||
}
|
||||
|
||||
if (bp[ndx + 1] == FULL_KEY) {
|
||||
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
bp = (u_int16_t *)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, bp[bp[0] - 1], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
bp = (u_int16_t *)bufp->page;
|
||||
} else {
|
||||
/* The data is all on one page. */
|
||||
tp = (char *)bp;
|
||||
off = bp[bp[0]];
|
||||
val->data = (u_char *)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,
|
||||
bp[bp[0] - 1], bufp, 0);
|
||||
if (!hashp->cpage)
|
||||
return (-1);
|
||||
hashp->cndx = 1;
|
||||
if (!((u_int16_t *)
|
||||
hashp->cpage->page)[0]) {
|
||||
hashp->cbucket++;
|
||||
hashp->cpage = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
val->size = collect_data(hashp, bufp, (int)len, set_current);
|
||||
if (val->size == -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, len);
|
||||
val->data = (u_char *)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(hashp, bufp, len, set)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
int len, set;
|
||||
{
|
||||
register u_int16_t *bp;
|
||||
register char *p;
|
||||
BUFHEAD *xbp;
|
||||
u_int16_t save_addr;
|
||||
int mylen, totlen;
|
||||
|
||||
p = bufp->page;
|
||||
bp = (u_int16_t *)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 = (char *)malloc(totlen)) == NULL)
|
||||
return (-1);
|
||||
if (set) {
|
||||
hashp->cndx = 1;
|
||||
if (bp[0] == 2) { /* No more buckets in chain */
|
||||
hashp->cpage = NULL;
|
||||
hashp->cbucket++;
|
||||
} else {
|
||||
hashp->cpage =
|
||||
__get_buf(hashp, bp[bp[0] - 1], bufp, 0);
|
||||
if (!hashp->cpage)
|
||||
return (-1);
|
||||
else if (!((u_int16_t *)hashp->cpage->page)[0]) {
|
||||
hashp->cbucket++;
|
||||
hashp->cpage = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
|
||||
if (!xbp || ((totlen =
|
||||
collect_data(hashp, xbp, len + mylen, set)) < 1))
|
||||
return (-1);
|
||||
}
|
||||
if (bufp->addr != save_addr) {
|
||||
errno = EINVAL; /* Out of buffers. */
|
||||
return (-1);
|
||||
}
|
||||
memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen);
|
||||
return (totlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the key and data for this big pair.
|
||||
*/
|
||||
extern int
|
||||
__big_keydata(hashp, bufp, key, val, set)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
DBT *key, *val;
|
||||
int set;
|
||||
{
|
||||
key->size = collect_key(hashp, bufp, 0, val, set);
|
||||
if (key->size == -1)
|
||||
return (-1);
|
||||
key->data = (u_char *)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(hashp, bufp, len, val, set)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
int len;
|
||||
DBT *val;
|
||||
int set;
|
||||
{
|
||||
BUFHEAD *xbp;
|
||||
char *p;
|
||||
int mylen, totlen;
|
||||
u_int16_t *bp, save_addr;
|
||||
|
||||
p = bufp->page;
|
||||
bp = (u_int16_t *)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 = (char *)malloc(totlen)) == NULL)
|
||||
return (-1);
|
||||
if (__big_return(hashp, bufp, 1, val, set))
|
||||
return (-1);
|
||||
} else {
|
||||
xbp = __get_buf(hashp, 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], mylen);
|
||||
return (totlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 => OK
|
||||
* -1 => error
|
||||
*/
|
||||
extern int
|
||||
__big_split(hashp, op, np, big_keyp, addr, obucket, ret)
|
||||
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 */
|
||||
u_int32_t obucket;/* Old Bucket */
|
||||
SPLIT_RETURN *ret;
|
||||
{
|
||||
register BUFHEAD *tmpp;
|
||||
register u_int16_t *tp;
|
||||
BUFHEAD *bp;
|
||||
DBT key, val;
|
||||
u_int32_t change;
|
||||
u_int16_t free_space, n, off;
|
||||
|
||||
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, key.size) != obucket);
|
||||
|
||||
if (ret->next_addr = __find_last_page(hashp, &big_keyp)) {
|
||||
if (!(ret->nextp =
|
||||
__get_buf(hashp, 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 */
|
||||
#ifdef DEBUG
|
||||
assert(np->ovfl == NULL);
|
||||
#endif
|
||||
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 = (u_int16_t *)tmpp->page;
|
||||
#ifdef DEBUG
|
||||
assert(FREESPACE(tp) >= OVFLSIZE);
|
||||
#endif
|
||||
n = tp[0];
|
||||
off = OFFSET(tp);
|
||||
free_space = FREESPACE(tp);
|
||||
tp[++n] = (u_int16_t)addr;
|
||||
tp[++n] = OVFLPAGE;
|
||||
tp[0] = n;
|
||||
OFFSET(tp) = off;
|
||||
FREESPACE(tp) = free_space - OVFLSIZE;
|
||||
|
||||
/*
|
||||
* 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 = (u_int16_t *)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;
|
||||
FREESPACE(tp) = free_space + OVFLSIZE;
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <db.h>
|
||||
#include "hash.h"
|
||||
#include "page.h"
|
||||
#include "extern.h"
|
||||
|
||||
static BUFHEAD *newbuf __P((HTAB *, u_int32_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.
|
||||
*/
|
||||
extern BUFHEAD *
|
||||
__get_buf(hashp, addr, prev_bp, newpage)
|
||||
HTAB *hashp;
|
||||
u_int32_t addr;
|
||||
BUFHEAD *prev_bp;
|
||||
int newpage; /* If prev_bp set, indicates a new overflow page. */
|
||||
{
|
||||
register BUFHEAD *bp;
|
||||
register u_int32_t is_disk_mask;
|
||||
register int is_disk, segment_ndx;
|
||||
SEGMENT segp;
|
||||
|
||||
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];
|
||||
#ifdef DEBUG
|
||||
assert(segp != NULL);
|
||||
#endif
|
||||
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 *)((ptrdiff_t)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(hashp, addr, prev_bp)
|
||||
HTAB *hashp;
|
||||
u_int32_t addr;
|
||||
BUFHEAD *prev_bp;
|
||||
{
|
||||
register BUFHEAD *bp; /* The buffer we're going to use */
|
||||
register BUFHEAD *xbp; /* Temp pointer */
|
||||
register BUFHEAD *next_xbp;
|
||||
SEGMENT segp;
|
||||
int segment_ndx;
|
||||
u_int16_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 = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL)
|
||||
return (NULL);
|
||||
#ifdef PURIFY
|
||||
memset(bp, 0xff, sizeof(BUFHEAD));
|
||||
#endif
|
||||
if ((bp->page = (char *)malloc(hashp->BSIZE)) == NULL) {
|
||||
free(bp);
|
||||
return (NULL);
|
||||
}
|
||||
#ifdef PURIFY
|
||||
memset(bp->page, 0xff, hashp->BSIZE);
|
||||
#endif
|
||||
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 = (u_int16_t *)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];
|
||||
#ifdef DEBUG
|
||||
assert(segp != NULL);
|
||||
#endif
|
||||
|
||||
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 = (u_int16_t *)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 ? 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);
|
||||
}
|
||||
|
||||
extern void
|
||||
__buf_init(hashp, nbytes)
|
||||
HTAB *hashp;
|
||||
int nbytes;
|
||||
{
|
||||
BUFHEAD *bfp;
|
||||
int npages;
|
||||
|
||||
bfp = &(hashp->bufhead);
|
||||
npages = (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;
|
||||
*/
|
||||
}
|
||||
|
||||
extern int
|
||||
__buf_free(hashp, do_free, to_disk)
|
||||
HTAB *hashp;
|
||||
int do_free, 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);
|
||||
}
|
||||
|
||||
extern void
|
||||
__reclaim_buf(hashp, bp)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bp;
|
||||
{
|
||||
bp->ovfl = 0;
|
||||
bp->addr = 0;
|
||||
bp->flags = 0;
|
||||
BUF_REMOVE(bp);
|
||||
LRU_INSERT(bp);
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash_func.c 8.2 (Berkeley) 2/21/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "hash.h"
|
||||
#include "page.h"
|
||||
#include "extern.h"
|
||||
|
||||
static u_int32_t hash1 __P((const void *, size_t));
|
||||
static u_int32_t hash2 __P((const void *, size_t));
|
||||
static u_int32_t hash3 __P((const void *, size_t));
|
||||
static u_int32_t hash4 __P((const void *, size_t));
|
||||
|
||||
/* Global default hash function */
|
||||
u_int32_t (*__default_hash) __P((const void *, size_t)) = hash4;
|
||||
|
||||
/*
|
||||
* 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 u_int32_t
|
||||
hash1(keyarg, len)
|
||||
const void *keyarg;
|
||||
register size_t len;
|
||||
{
|
||||
register const u_char *key;
|
||||
register u_int32_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 u_int32_t
|
||||
hash2(keyarg, len)
|
||||
const void *keyarg;
|
||||
size_t len;
|
||||
{
|
||||
register const u_char *e, *key;
|
||||
register u_int32_t h;
|
||||
register u_char 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 u_int32_t
|
||||
hash3(keyarg, len)
|
||||
const void *keyarg;
|
||||
register size_t len;
|
||||
{
|
||||
register const u_char *key;
|
||||
register size_t loop;
|
||||
register u_int32_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);
|
||||
}
|
||||
|
||||
/* Hash function from Chris Torek. */
|
||||
static u_int32_t
|
||||
hash4(keyarg, len)
|
||||
const void *keyarg;
|
||||
register size_t len;
|
||||
{
|
||||
register const u_char *key;
|
||||
register size_t loop;
|
||||
register u_int32_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);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <db.h>
|
||||
|
||||
u_int32_t __log2 __P((u_int32_t));
|
||||
|
||||
u_int32_t
|
||||
__log2(num)
|
||||
u_int32_t num;
|
||||
{
|
||||
register u_int32_t i, limit;
|
||||
|
||||
limit = 1;
|
||||
for (i = 0; limit < num; limit = limit << 1, i++);
|
||||
return (i);
|
||||
}
|
||||
@@ -0,0 +1,944 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* 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>
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <db.h>
|
||||
#include "hash.h"
|
||||
#include "page.h"
|
||||
#include "extern.h"
|
||||
|
||||
static u_int32_t *fetch_bitmap __P((HTAB *, int));
|
||||
static u_int32_t first_free __P((u_int32_t));
|
||||
static int open_temp __P((HTAB *));
|
||||
static u_int16_t overflow_page __P((HTAB *));
|
||||
static void putpair __P((char *, const DBT *, const DBT *));
|
||||
static void squeeze_key __P((u_int16_t *, const DBT *, const DBT *));
|
||||
static int ugly_split
|
||||
__P((HTAB *, u_int32_t, BUFHEAD *, BUFHEAD *, int, int));
|
||||
|
||||
#define PAGE_INIT(P) { \
|
||||
((u_int16_t *)(P))[0] = 0; \
|
||||
((u_int16_t *)(P))[1] = hashp->BSIZE - 3 * sizeof(u_int16_t); \
|
||||
((u_int16_t *)(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(p, key, val)
|
||||
char *p;
|
||||
const DBT *key, *val;
|
||||
{
|
||||
register u_int16_t *bp, n, off;
|
||||
|
||||
bp = (u_int16_t *)p;
|
||||
|
||||
/* Enter the key first. */
|
||||
n = bp[0];
|
||||
|
||||
off = OFFSET(bp) - key->size;
|
||||
memmove(p + off, key->data, key->size);
|
||||
bp[++n] = off;
|
||||
|
||||
/* Now the data. */
|
||||
off -= val->size;
|
||||
memmove(p + off, val->data, val->size);
|
||||
bp[++n] = off;
|
||||
|
||||
/* Adjust page info. */
|
||||
bp[0] = n;
|
||||
bp[n + 1] = off - ((n + 3) * sizeof(u_int16_t));
|
||||
bp[n + 2] = off;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 OK
|
||||
* -1 error
|
||||
*/
|
||||
extern int
|
||||
__delpair(hashp, bufp, ndx)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
register int ndx;
|
||||
{
|
||||
register u_int16_t *bp, newoff;
|
||||
register int n;
|
||||
u_int16_t pairlen;
|
||||
|
||||
bp = (u_int16_t *)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 */
|
||||
register int i;
|
||||
register char *src = bufp->page + (int)OFFSET(bp);
|
||||
register char *dst = src + (int)pairlen;
|
||||
memmove(dst, src, 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;
|
||||
bp[n - 1] = bp[n + 1] + pairlen + 2 * sizeof(u_int16_t);
|
||||
bp[0] = n - 2;
|
||||
hashp->NKEYS--;
|
||||
|
||||
bufp->flags |= BUF_MOD;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Returns:
|
||||
* 0 ==> OK
|
||||
* -1 ==> Error
|
||||
*/
|
||||
extern int
|
||||
__split_page(hashp, obucket, nbucket)
|
||||
HTAB *hashp;
|
||||
u_int32_t obucket, nbucket;
|
||||
{
|
||||
register BUFHEAD *new_bufp, *old_bufp;
|
||||
register u_int16_t *ino;
|
||||
register char *np;
|
||||
DBT key, val;
|
||||
int n, ndx, retval;
|
||||
u_int16_t copyto, diff, off, moved;
|
||||
char *op;
|
||||
|
||||
copyto = (u_int16_t)hashp->BSIZE;
|
||||
off = (u_int16_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 = (u_int16_t *)(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 = (u_char *)op + ino[n];
|
||||
key.size = off - ino[n];
|
||||
|
||||
if (__call_hash(hashp, key.data, key.size) == obucket) {
|
||||
/* Don't switch page */
|
||||
diff = copyto - off;
|
||||
if (diff) {
|
||||
copyto = ino[n + 1] + diff;
|
||||
memmove(op + copyto, op + ino[n + 1],
|
||||
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 = (u_char *)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;
|
||||
FREESPACE(ino) = copyto - sizeof(u_int16_t) * (ino[0] + 3);
|
||||
OFFSET(ino) = copyto;
|
||||
|
||||
#ifdef DEBUG3
|
||||
(void)fprintf(stderr, "split %d/%d\n",
|
||||
((u_int16_t *)np)[0] / 2,
|
||||
((u_int16_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(hashp, obucket, old_bufp, new_bufp, copyto, moved)
|
||||
HTAB *hashp;
|
||||
u_int32_t obucket; /* Same as __split_page. */
|
||||
BUFHEAD *old_bufp, *new_bufp;
|
||||
int copyto; /* First byte on page which contains key/data values. */
|
||||
int moved; /* Number of pairs moved to new page. */
|
||||
{
|
||||
register BUFHEAD *bufp; /* Buffer header for ino */
|
||||
register u_int16_t *ino; /* Page keys come off of */
|
||||
register u_int16_t *np; /* New page */
|
||||
register u_int16_t *op; /* Page keys go on to if they aren't moving */
|
||||
|
||||
BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
|
||||
DBT key, val;
|
||||
SPLIT_RETURN ret;
|
||||
u_int16_t n, off, ov_addr, scopyto;
|
||||
char *cino; /* Character value of ino */
|
||||
|
||||
bufp = old_bufp;
|
||||
ino = (u_int16_t *)old_bufp->page;
|
||||
np = (u_int16_t *)new_bufp->page;
|
||||
op = (u_int16_t *)old_bufp->page;
|
||||
last_bfp = NULL;
|
||||
scopyto = (u_int16_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, bufp->addr, obucket, &ret))
|
||||
return (-1);
|
||||
old_bufp = ret.oldp;
|
||||
if (!old_bufp)
|
||||
return (-1);
|
||||
op = (u_int16_t *)old_bufp->page;
|
||||
new_bufp = ret.newp;
|
||||
if (!new_bufp)
|
||||
return (-1);
|
||||
np = (u_int16_t *)new_bufp->page;
|
||||
bufp = ret.nextp;
|
||||
if (!bufp)
|
||||
return (0);
|
||||
cino = (char *)bufp->page;
|
||||
ino = (u_int16_t *)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);
|
||||
FREESPACE(ino) =
|
||||
scopyto - sizeof(u_int16_t) * (ino[0] + 3);
|
||||
OFFSET(ino) = scopyto;
|
||||
|
||||
bufp = __get_buf(hashp, ov_addr, bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
|
||||
ino = (u_int16_t *)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 *)ino;
|
||||
key.data = (u_char *)cino + ino[n];
|
||||
key.size = off - ino[n];
|
||||
val.data = (u_char *)cino + ino[n + 1];
|
||||
val.size = ino[n] - ino[n + 1];
|
||||
off = ino[n + 1];
|
||||
|
||||
if (__call_hash(hashp, key.data, key.size) == obucket) {
|
||||
/* Keep on old page */
|
||||
if (PAIRFITS(op, (&key), (&val)))
|
||||
putpair((char *)op, &key, &val);
|
||||
else {
|
||||
old_bufp =
|
||||
__add_ovflpage(hashp, old_bufp);
|
||||
if (!old_bufp)
|
||||
return (-1);
|
||||
op = (u_int16_t *)old_bufp->page;
|
||||
putpair((char *)op, &key, &val);
|
||||
}
|
||||
old_bufp->flags |= BUF_MOD;
|
||||
} else {
|
||||
/* Move to new page */
|
||||
if (PAIRFITS(np, (&key), (&val)))
|
||||
putpair((char *)np, &key, &val);
|
||||
else {
|
||||
new_bufp =
|
||||
__add_ovflpage(hashp, new_bufp);
|
||||
if (!new_bufp)
|
||||
return (-1);
|
||||
np = (u_int16_t *)new_bufp->page;
|
||||
putpair((char *)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
|
||||
*/
|
||||
extern int
|
||||
__addel(hashp, bufp, key, val)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
const DBT *key, *val;
|
||||
{
|
||||
register u_int16_t *bp, *sop;
|
||||
int do_expand;
|
||||
|
||||
bp = (u_int16_t *)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, bp[bp[0] - 1], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
bp = (u_int16_t *)bufp->page;
|
||||
} else
|
||||
/* Try to squeeze key on this page */
|
||||
if (FREESPACE(bp) > PAIRSIZE(key, val)) {
|
||||
squeeze_key(bp, key, val);
|
||||
return (0);
|
||||
} else {
|
||||
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
|
||||
if (!bufp)
|
||||
return (-1);
|
||||
bp = (u_int16_t *)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 = (u_int16_t *)bufp->page;
|
||||
|
||||
if (PAIRFITS(sop, key, val))
|
||||
putpair((char *)sop, key, val);
|
||||
else
|
||||
if (__big_insert(hashp, bufp, key, val))
|
||||
return (-1);
|
||||
}
|
||||
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
|
||||
*/
|
||||
extern BUFHEAD *
|
||||
__add_ovflpage(hashp, bufp)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *bufp;
|
||||
{
|
||||
register u_int16_t *sp;
|
||||
u_int16_t ndx, ovfl_num;
|
||||
#ifdef DEBUG1
|
||||
int tmp1, tmp2;
|
||||
#endif
|
||||
sp = (u_int16_t *)bufp->page;
|
||||
|
||||
/* Check if we are dynamically determining the fill factor */
|
||||
if (hashp->FFACTOR == DEF_FFACTOR) {
|
||||
hashp->FFACTOR = 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, 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);
|
||||
sp[ndx + 3] = FREESPACE(sp) - 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
|
||||
*/
|
||||
extern int
|
||||
__get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap)
|
||||
HTAB *hashp;
|
||||
char *p;
|
||||
u_int32_t bucket;
|
||||
int is_bucket, is_disk, is_bitmap;
|
||||
{
|
||||
register int fd, page, size;
|
||||
int rsize;
|
||||
u_int16_t *bp;
|
||||
|
||||
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 ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) ||
|
||||
((rsize = read(fd, p, size)) == -1))
|
||||
return (-1);
|
||||
bp = (u_int16_t *)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) {
|
||||
register int i, max;
|
||||
|
||||
if (is_bitmap) {
|
||||
max = hashp->BSIZE >> 2; /* divide by 4 */
|
||||
for (i = 0; i < max; i++)
|
||||
M_32_SWAP(((int *)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
|
||||
*/
|
||||
extern int
|
||||
__put_page(hashp, p, bucket, is_bucket, is_bitmap)
|
||||
HTAB *hashp;
|
||||
char *p;
|
||||
u_int32_t bucket;
|
||||
int is_bucket, is_bitmap;
|
||||
{
|
||||
register int fd, page, size;
|
||||
int wsize;
|
||||
|
||||
size = hashp->BSIZE;
|
||||
if ((hashp->fp == -1) && open_temp(hashp))
|
||||
return (-1);
|
||||
fd = hashp->fp;
|
||||
|
||||
if (hashp->LORDER != BYTE_ORDER) {
|
||||
register int i;
|
||||
register int max;
|
||||
|
||||
if (is_bitmap) {
|
||||
max = hashp->BSIZE >> 2; /* divide by 4 */
|
||||
for (i = 0; i < max; i++)
|
||||
M_32_SWAP(((int *)p)[i]);
|
||||
} else {
|
||||
max = ((u_int16_t *)p)[0] + 2;
|
||||
for (i = 0; i <= max; i++)
|
||||
M_16_SWAP(((u_int16_t *)p)[i]);
|
||||
}
|
||||
}
|
||||
if (is_bucket)
|
||||
page = BUCKET_TO_PAGE(bucket);
|
||||
else
|
||||
page = OADDR_TO_PAGE(bucket);
|
||||
if ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) ||
|
||||
((wsize = write(fd, p, size)) == -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.
|
||||
*/
|
||||
extern int
|
||||
__ibitmap(hashp, pnum, nbits, ndx)
|
||||
HTAB *hashp;
|
||||
int pnum, nbits, ndx;
|
||||
{
|
||||
u_int32_t *ip;
|
||||
int clearbytes, clearints;
|
||||
|
||||
if ((ip = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
|
||||
return (1);
|
||||
hashp->nmaps++;
|
||||
clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
|
||||
clearbytes = clearints << INT_TO_BYTE;
|
||||
(void)memset((char *)ip, 0, clearbytes);
|
||||
(void)memset(((char *)ip) + clearbytes, 0xFF,
|
||||
hashp->BSIZE - clearbytes);
|
||||
ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
|
||||
SETBIT(ip, 0);
|
||||
hashp->BITMAPS[ndx] = (u_int16_t)pnum;
|
||||
hashp->mapp[ndx] = ip;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
first_free(map)
|
||||
u_int32_t map;
|
||||
{
|
||||
register u_int32_t i, mask;
|
||||
|
||||
mask = 0x1;
|
||||
for (i = 0; i < BITS_PER_MAP; i++) {
|
||||
if (!(mask & map))
|
||||
return (i);
|
||||
mask = mask << 1;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
static u_int16_t
|
||||
overflow_page(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
register u_int32_t *freep;
|
||||
register int max_free, offset, splitnum;
|
||||
u_int16_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 = (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 = hashp->LAST_FREED >>(hashp->BSHIFT + BYTE_SHIFT);
|
||||
for ( i = first_page; i <= free_page; i++ ) {
|
||||
if (!(freep = (u_int32_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);
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
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.
|
||||
*/
|
||||
extern void
|
||||
__free_ovflpage(hashp, obufp)
|
||||
HTAB *hashp;
|
||||
BUFHEAD *obufp;
|
||||
{
|
||||
register u_int16_t addr;
|
||||
u_int32_t *freep;
|
||||
int bit_address, free_page, free_bit;
|
||||
u_int16_t ndx;
|
||||
|
||||
addr = obufp->addr;
|
||||
#ifdef DEBUG1
|
||||
(void)fprintf(stderr, "Freeing %d\n", addr);
|
||||
#endif
|
||||
ndx = (((u_int16_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 = (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);
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (!freep)
|
||||
assert(0);
|
||||
#endif
|
||||
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(hashp)
|
||||
HTAB *hashp;
|
||||
{
|
||||
sigset_t set, oset;
|
||||
static char namestr[] = "_hashXXXXXX";
|
||||
|
||||
/* 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, 1);
|
||||
}
|
||||
(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(sp, key, val)
|
||||
u_int16_t *sp;
|
||||
const DBT *key, *val;
|
||||
{
|
||||
register char *p;
|
||||
u_int16_t free_space, n, off, pageno;
|
||||
|
||||
p = (char *)sp;
|
||||
n = sp[0];
|
||||
free_space = FREESPACE(sp);
|
||||
off = OFFSET(sp);
|
||||
|
||||
pageno = sp[n - 1];
|
||||
off -= key->size;
|
||||
sp[n - 1] = off;
|
||||
memmove(p + off, key->data, key->size);
|
||||
off -= val->size;
|
||||
sp[n] = off;
|
||||
memmove(p + off, val->data, val->size);
|
||||
sp[0] = n + 2;
|
||||
sp[n + 1] = pageno;
|
||||
sp[n + 2] = OVFLPAGE;
|
||||
FREESPACE(sp) = free_space - PAIRSIZE(key, val);
|
||||
OFFSET(sp) = off;
|
||||
}
|
||||
|
||||
static u_int32_t *
|
||||
fetch_bitmap(hashp, ndx)
|
||||
HTAB *hashp;
|
||||
int ndx;
|
||||
{
|
||||
if (ndx >= hashp->nmaps)
|
||||
return (NULL);
|
||||
if ((hashp->mapp[ndx] = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
|
||||
return (NULL);
|
||||
if (__get_page(hashp,
|
||||
(char *)hashp->mapp[ndx], hashp->BITMAPS[ndx], 0, 1, 1)) {
|
||||
free(hashp->mapp[ndx]);
|
||||
return (NULL);
|
||||
}
|
||||
return (hashp->mapp[ndx]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG4
|
||||
int
|
||||
print_chain(addr)
|
||||
int addr;
|
||||
{
|
||||
BUFHEAD *bufp;
|
||||
short *bp, oaddr;
|
||||
|
||||
(void)fprintf(stderr, "%d ", addr);
|
||||
bufp = __get_buf(hashp, addr, NULL, 0);
|
||||
bp = (short *)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, (int)oaddr, bufp, 0);
|
||||
bp = (short *)bufp->page;
|
||||
}
|
||||
(void)fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)ndbm.c 8.4 (Berkeley) 7/21/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
* This package provides a dbm compatible interface to the new hashing
|
||||
* package described in db(3).
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ndbm.h>
|
||||
#include "hash.h"
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* *DBM on success
|
||||
* NULL on failure
|
||||
*/
|
||||
extern DBM *
|
||||
dbm_open(file, flags, mode)
|
||||
const char *file;
|
||||
int flags, 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)strcpy(path, file);
|
||||
(void)strcat(path, DBM_SUFFIX);
|
||||
return ((DBM *)__hash_open(path, flags, mode, &info, 0));
|
||||
}
|
||||
|
||||
extern void
|
||||
dbm_close(db)
|
||||
DBM *db;
|
||||
{
|
||||
(void)(db->close)(db);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* DATUM on success
|
||||
* NULL on failure
|
||||
*/
|
||||
extern datum
|
||||
dbm_fetch(db, key)
|
||||
DBM *db;
|
||||
datum key;
|
||||
{
|
||||
datum retval;
|
||||
int status;
|
||||
|
||||
status = (db->get)(db, (DBT *)&key, (DBT *)&retval, 0);
|
||||
if (status) {
|
||||
retval.dptr = NULL;
|
||||
retval.dsize = 0;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* DATUM on success
|
||||
* NULL on failure
|
||||
*/
|
||||
extern datum
|
||||
dbm_firstkey(db)
|
||||
DBM *db;
|
||||
{
|
||||
int status;
|
||||
datum retdata, retkey;
|
||||
|
||||
status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_FIRST);
|
||||
if (status)
|
||||
retkey.dptr = NULL;
|
||||
return (retkey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* DATUM on success
|
||||
* NULL on failure
|
||||
*/
|
||||
extern datum
|
||||
dbm_nextkey(db)
|
||||
DBM *db;
|
||||
{
|
||||
int status;
|
||||
datum retdata, retkey;
|
||||
|
||||
status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_NEXT);
|
||||
if (status)
|
||||
retkey.dptr = NULL;
|
||||
return (retkey);
|
||||
}
|
||||
/*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* <0 failure
|
||||
*/
|
||||
extern int
|
||||
dbm_delete(db, key)
|
||||
DBM *db;
|
||||
datum key;
|
||||
{
|
||||
int status;
|
||||
|
||||
status = (db->del)(db, (DBT *)&key, 0);
|
||||
if (status)
|
||||
return (-1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* <0 failure
|
||||
* 1 if DBM_INSERT and entry exists
|
||||
*/
|
||||
extern int
|
||||
dbm_store(db, key, content, flags)
|
||||
DBM *db;
|
||||
datum key, content;
|
||||
int flags;
|
||||
{
|
||||
return ((db->put)(db, (DBT *)&key, (DBT *)&content,
|
||||
(flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
|
||||
}
|
||||
|
||||
extern int
|
||||
dbm_error(db)
|
||||
DBM *db;
|
||||
{
|
||||
HTAB *hp;
|
||||
|
||||
hp = (HTAB *)db->internal;
|
||||
return (hp->errno);
|
||||
}
|
||||
|
||||
extern int
|
||||
dbm_clearerr(db)
|
||||
DBM *db;
|
||||
{
|
||||
HTAB *hp;
|
||||
|
||||
hp = (HTAB *)db->internal;
|
||||
hp->errno = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
extern int
|
||||
dbm_dirfno(db)
|
||||
DBM *db;
|
||||
{
|
||||
return(((HTAB *)db->internal)->fp);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)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(u_int16_t) + (K)->size + (D)->size)
|
||||
#define BIGOVERHEAD (4*sizeof(u_int16_t))
|
||||
#define KEYSIZE(K) (4*sizeof(u_int16_t) + (K)->size);
|
||||
#define OVFLSIZE (2*sizeof(u_int16_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(u_int16_t))
|
||||
|
||||
typedef struct {
|
||||
BUFHEAD *newp;
|
||||
BUFHEAD *oldp;
|
||||
BUFHEAD *nextp;
|
||||
u_int16_t next_addr;
|
||||
} SPLIT_RETURN;
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)mpool.h 8.2 (Berkeley) 7/14/94
|
||||
*/
|
||||
|
||||
#include <sys/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 */
|
||||
u_int8_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 */
|
||||
u_long pagesize; /* file page size */
|
||||
int fd; /* file descriptor */
|
||||
/* page in conversion routine */
|
||||
void (*pgin) __P((void *, pgno_t, void *));
|
||||
/* page out conversion routine */
|
||||
void (*pgout) __P((void *, pgno_t, void *));
|
||||
void *pgcookie; /* cookie for page in/out routines */
|
||||
#ifdef STATISTICS
|
||||
u_long cachehit;
|
||||
u_long cachemiss;
|
||||
u_long pagealloc;
|
||||
u_long pageflush;
|
||||
u_long pageget;
|
||||
u_long pagenew;
|
||||
u_long pageput;
|
||||
u_long pageread;
|
||||
u_long pagewrite;
|
||||
#endif
|
||||
} MPOOL;
|
||||
|
||||
__BEGIN_DECLS
|
||||
MPOOL *mpool_open __P((void *, int, pgno_t, pgno_t));
|
||||
void mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *),
|
||||
void (*)(void *, pgno_t, void *), void *));
|
||||
void *mpool_new __P((MPOOL *, pgno_t *));
|
||||
void *mpool_get __P((MPOOL *, pgno_t, u_int));
|
||||
int mpool_put __P((MPOOL *, void *, u_int));
|
||||
int mpool_sync __P((MPOOL *));
|
||||
int mpool_close __P((MPOOL *));
|
||||
#ifdef STATISTICS
|
||||
void mpool_stat __P((MPOOL *));
|
||||
#endif
|
||||
__END_DECLS
|
||||
@@ -0,0 +1,463 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)mpool.c 8.5 (Berkeley) 7/26/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <db.h>
|
||||
|
||||
#define __MPOOLINTERFACE_PRIVATE
|
||||
#include <mpool.h>
|
||||
|
||||
static BKT *mpool_bkt __P((MPOOL *));
|
||||
static BKT *mpool_look __P((MPOOL *, pgno_t));
|
||||
static int mpool_write __P((MPOOL *, BKT *));
|
||||
|
||||
/*
|
||||
* mpool_open --
|
||||
* Initialize a memory pool.
|
||||
*/
|
||||
MPOOL *
|
||||
mpool_open(key, fd, pagesize, maxcache)
|
||||
void *key;
|
||||
int fd;
|
||||
pgno_t pagesize, 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 = sb.st_size / pagesize;
|
||||
mp->pagesize = pagesize;
|
||||
mp->fd = fd;
|
||||
return (mp);
|
||||
}
|
||||
|
||||
/*
|
||||
* mpool_filter --
|
||||
* Initialize input/output filters.
|
||||
*/
|
||||
void
|
||||
mpool_filter(mp, pgin, pgout, pgcookie)
|
||||
MPOOL *mp;
|
||||
void (*pgin) __P((void *, pgno_t, void *));
|
||||
void (*pgout) __P((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(mp, pgnoaddr)
|
||||
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.
|
||||
*/
|
||||
void *
|
||||
mpool_get(mp, pgno, flags)
|
||||
MPOOL *mp;
|
||||
pgno_t pgno;
|
||||
u_int flags; /* XXX not used? */
|
||||
{
|
||||
struct _hqh *head;
|
||||
BKT *bp;
|
||||
off_t off;
|
||||
int 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 (lseek(mp->fd, off, SEEK_SET) != off)
|
||||
return (NULL);
|
||||
if ((nr = read(mp->fd, bp->page, mp->pagesize)) != 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.
|
||||
*/
|
||||
int
|
||||
mpool_put(mp, page, flags)
|
||||
MPOOL *mp;
|
||||
void *page;
|
||||
u_int flags;
|
||||
{
|
||||
BKT *bp;
|
||||
|
||||
#ifdef STATISTICS
|
||||
++mp->pageput;
|
||||
#endif
|
||||
bp = (BKT *)((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(mp)
|
||||
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(mp)
|
||||
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(mp)
|
||||
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;
|
||||
spage = bp->page;
|
||||
memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
|
||||
bp->page = spage;
|
||||
}
|
||||
#endif
|
||||
return (bp);
|
||||
}
|
||||
|
||||
new: if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
|
||||
return (NULL);
|
||||
#ifdef STATISTICS
|
||||
++mp->pagealloc;
|
||||
#endif
|
||||
#if defined(DEBUG) || defined(PURIFY)
|
||||
memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
|
||||
#endif
|
||||
bp->page = (char *)bp + sizeof(BKT);
|
||||
++mp->curcache;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* mpool_write
|
||||
* Write a page to disk.
|
||||
*/
|
||||
static int
|
||||
mpool_write(mp, bp)
|
||||
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 (lseek(mp->fd, off, SEEK_SET) != off)
|
||||
return (RET_ERROR);
|
||||
if (write(mp->fd, bp->page, mp->pagesize) != mp->pagesize)
|
||||
return (RET_ERROR);
|
||||
|
||||
bp->flags &= ~MPOOL_DIRTY;
|
||||
return (RET_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* mpool_look
|
||||
* Lookup a page in the cache.
|
||||
*/
|
||||
static BKT *
|
||||
mpool_look(mp, pgno)
|
||||
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;
|
||||
char *sep;
|
||||
|
||||
(void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
|
||||
(void)fprintf(stderr,
|
||||
"page size %lu, cacheing %lu pages of %lu page max cache\n",
|
||||
mp->pagesize, mp->curcache, 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
|
||||
@@ -0,0 +1,79 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)ndbm.h 8.1 (Berkeley) 6/2/93
|
||||
*/
|
||||
|
||||
#ifndef _NDBM_H_
|
||||
#define _NDBM_H_
|
||||
|
||||
#include <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 {
|
||||
char *dptr;
|
||||
int dsize;
|
||||
} datum;
|
||||
|
||||
typedef DB DBM;
|
||||
#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE
|
||||
|
||||
__BEGIN_DECLS
|
||||
void dbm_close __P((DBM *));
|
||||
int dbm_delete __P((DBM *, datum));
|
||||
datum dbm_fetch __P((DBM *, datum));
|
||||
datum dbm_firstkey __P((DBM *));
|
||||
long dbm_forder __P((DBM *, datum));
|
||||
datum dbm_nextkey __P((DBM *));
|
||||
DBM *dbm_open __P((const char *, int, int));
|
||||
int dbm_store __P((DBM *, datum, datum, int));
|
||||
int dbm_dirfno __P((DBM *));
|
||||
int dbm_error __P((DBM *));
|
||||
int dbm_clearerr __P((DBM *));
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_NDBM_H_ */
|
||||
@@ -0,0 +1,54 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.3 (Berkeley) 6/4/94
|
||||
*/
|
||||
|
||||
#include "../btree/extern.h"
|
||||
|
||||
int __rec_close __P((DB *));
|
||||
int __rec_delete __P((const DB *, const DBT *, u_int));
|
||||
int __rec_dleaf __P((BTREE *, PAGE *, u_int32_t));
|
||||
int __rec_fd __P((const DB *));
|
||||
int __rec_fmap __P((BTREE *, recno_t));
|
||||
int __rec_fout __P((BTREE *));
|
||||
int __rec_fpipe __P((BTREE *, recno_t));
|
||||
int __rec_get __P((const DB *, const DBT *, DBT *, u_int));
|
||||
int __rec_iput __P((BTREE *, recno_t, const DBT *, u_int));
|
||||
int __rec_put __P((const DB *dbp, DBT *, const DBT *, u_int));
|
||||
int __rec_ret __P((BTREE *, EPG *, recno_t, DBT *, DBT *));
|
||||
EPG *__rec_search __P((BTREE *, recno_t, enum SRCHOP));
|
||||
int __rec_seq __P((const DB *, DBT *, DBT *, u_int));
|
||||
int __rec_sync __P((const DB *, u_int));
|
||||
int __rec_vmap __P((BTREE *, recno_t));
|
||||
int __rec_vout __P((BTREE *));
|
||||
int __rec_vpipe __P((BTREE *, recno_t));
|
||||
@@ -0,0 +1,182 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_close.c 8.6 (Berkeley) 8/18/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <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(dbp)
|
||||
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(dbp, flags)
|
||||
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) != 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) != 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);
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_delete.c 8.7 (Berkeley) 7/14/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "recno.h"
|
||||
|
||||
static int rec_rdelete __P((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(dbp, key, flags)
|
||||
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(t, nrec)
|
||||
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, 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(t, h, index)
|
||||
BTREE *t;
|
||||
PAGE *h;
|
||||
u_int32_t index;
|
||||
{
|
||||
RLEAF *rl;
|
||||
indx_t *ip, cnt, offset;
|
||||
u_int32_t nbytes;
|
||||
char *from;
|
||||
void *to;
|
||||
|
||||
/*
|
||||
* 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, index);
|
||||
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 *)h + h->upper;
|
||||
memmove(from + nbytes, from, (char *)to - from);
|
||||
h->upper += nbytes;
|
||||
|
||||
offset = h->linp[index];
|
||||
for (cnt = &h->linp[index] - (ip = &h->linp[0]); cnt--; ++ip)
|
||||
if (ip[0] < offset)
|
||||
ip[0] += nbytes;
|
||||
for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
|
||||
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
|
||||
h->lower -= sizeof(indx_t);
|
||||
--t->bt_nrecs;
|
||||
return (RET_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_get.c 8.9 (Berkeley) 8/18/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <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(dbp, key, data, flags)
|
||||
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(t, top)
|
||||
BTREE *t;
|
||||
recno_t top;
|
||||
{
|
||||
DBT data;
|
||||
recno_t nrec;
|
||||
size_t len;
|
||||
int ch;
|
||||
u_char *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(t, top)
|
||||
BTREE *t;
|
||||
recno_t top;
|
||||
{
|
||||
DBT data;
|
||||
recno_t nrec;
|
||||
indx_t len;
|
||||
size_t sz;
|
||||
int bval, ch;
|
||||
u_char *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 - (u_char *)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 - (u_char *)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 = (u_char *)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(t, top)
|
||||
BTREE *t;
|
||||
recno_t top;
|
||||
{
|
||||
DBT data;
|
||||
recno_t nrec;
|
||||
u_char *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 = (u_char *)t->bt_cmap;
|
||||
ep = (u_char *)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(t, top)
|
||||
BTREE *t;
|
||||
recno_t top;
|
||||
{
|
||||
DBT data;
|
||||
u_char *sp, *ep;
|
||||
recno_t nrec;
|
||||
int bval;
|
||||
|
||||
sp = (u_char *)t->bt_cmap;
|
||||
ep = (u_char *)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 - (u_char *)data.data;
|
||||
if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
|
||||
return (RET_ERROR);
|
||||
++sp;
|
||||
}
|
||||
t->bt_cmap = (caddr_t)sp;
|
||||
return (RET_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_open.c 8.10 (Berkeley) 9/1/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <db.h>
|
||||
#include "recno.h"
|
||||
|
||||
DB *
|
||||
__rec_open(fname, flags, mode, openinfo, dflags)
|
||||
const char *fname;
|
||||
int flags, mode, dflags;
|
||||
const RECNOINFO *openinfo;
|
||||
{
|
||||
BTREE *t;
|
||||
BTREEINFO btopeninfo;
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
struct stat sb;
|
||||
int rfd, sverrno;
|
||||
|
||||
/* Open the user's file -- if this fails, we're done. */
|
||||
if (fname != NULL && (rfd = open(fname, flags, mode)) < 0)
|
||||
return (NULL);
|
||||
|
||||
/* Create a btree in memory (backed by disk). */
|
||||
dbp = NULL;
|
||||
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 {
|
||||
#ifdef MMAP_NOT_AVAILABLE
|
||||
/*
|
||||
* 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_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(dbp)
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <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(dbp, key, data, flags)
|
||||
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(t, nrec, data, flags)
|
||||
BTREE *t;
|
||||
recno_t nrec;
|
||||
const DBT *data;
|
||||
u_int flags;
|
||||
{
|
||||
DBT tdata;
|
||||
EPG *e;
|
||||
PAGE *h;
|
||||
indx_t index, nxtindex;
|
||||
pgno_t pg;
|
||||
u_int32_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 *)db = pg;
|
||||
*(u_int32_t *)(db + sizeof(pgno_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;
|
||||
index = 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:
|
||||
++index;
|
||||
break;
|
||||
case R_IBEFORE:
|
||||
break;
|
||||
default:
|
||||
if (nrec < t->bt_nrecs &&
|
||||
__rec_dleaf(t, h, index) == 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 (h->upper - h->lower < nbytes + sizeof(indx_t)) {
|
||||
status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
|
||||
if (status == RET_SUCCESS)
|
||||
++t->bt_nrecs;
|
||||
return (status);
|
||||
}
|
||||
|
||||
if (index < (nxtindex = NEXTINDEX(h)))
|
||||
memmove(h->linp + index + 1, h->linp + index,
|
||||
(nxtindex - index) * sizeof(indx_t));
|
||||
h->lower += sizeof(indx_t);
|
||||
|
||||
h->linp[index] = h->upper -= nbytes;
|
||||
dest = (char *)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);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_search.c 8.4 (Berkeley) 7/14/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <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(t, recno, op)
|
||||
BTREE *t;
|
||||
recno_t recno;
|
||||
enum SRCHOP op;
|
||||
{
|
||||
register indx_t index;
|
||||
register 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 (index = 0, top = NEXTINDEX(h);;) {
|
||||
r = GETRINTERNAL(h, index);
|
||||
if (++index == top || total + r->nrecs > recno)
|
||||
break;
|
||||
total += r->nrecs;
|
||||
}
|
||||
|
||||
BT_PUSH(t, pg, index - 1);
|
||||
|
||||
pg = r->pgno;
|
||||
switch (op) {
|
||||
case SDELETE:
|
||||
--GETRINTERNAL(h, (index - 1))->nrecs;
|
||||
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
|
||||
break;
|
||||
case SINSERT:
|
||||
++GETRINTERNAL(h, (index - 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);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)rec_seq.c 8.3 (Berkeley) 7/14/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <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(dbp, key, data, flags)
|
||||
const DB *dbp;
|
||||
DBT *key, *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);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)rec_utils.c 8.6 (Berkeley) 7/16/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <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(t, e, nrec, key, data)
|
||||
BTREE *t;
|
||||
EPG *e;
|
||||
recno_t nrec;
|
||||
DBT *key, *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);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*-
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)recno.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
enum SRCHOP { SDELETE, SINSERT, SEARCH}; /* Rec_search operation. */
|
||||
|
||||
#include "../btree/btree.h"
|
||||
#include "extern.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
+2
-2
@@ -21,11 +21,11 @@
|
||||
#
|
||||
subdir := dirent
|
||||
|
||||
headers := dirent.h dirstream.h
|
||||
headers := dirent.h
|
||||
routines := opendir closedir readdir rewinddir \
|
||||
seekdir telldir scandir alphasort \
|
||||
getdents dirfd
|
||||
distribute := direct.h
|
||||
distribute := direct.h dirstream.h
|
||||
|
||||
tests := list tst-seekdir
|
||||
|
||||
|
||||
+3
-3
@@ -73,9 +73,9 @@ enum
|
||||
#endif
|
||||
|
||||
|
||||
/* Get the system-dependent definition of `DIR',
|
||||
the data type of directory stream objects. */
|
||||
#include <dirstream.h>
|
||||
/* This is the data type of directory stream objects.
|
||||
The actual structure is opaque to users. */
|
||||
typedef struct __dirstream DIR;
|
||||
|
||||
/* Open a directory stream on NAME.
|
||||
Return a DIR stream on the directory, or NULL if it could not be opened. */
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -19,6 +19,7 @@ Cambridge, MA 02139, USA. */
|
||||
#include <ansidecl.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int
|
||||
DEFUN(scandir, (dir, namelist, select, cmp),
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*.gz *.Z *.tar *.tgz
|
||||
=*
|
||||
TODO COPYING* AUTHORS copyr-* copying.*
|
||||
glibc-*
|
||||
distinfo
|
||||
+62
-2
@@ -1,3 +1,5 @@
|
||||
# Makefile for elf subdirectory of GNU C Library.
|
||||
|
||||
# Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
@@ -16,8 +18,66 @@
|
||||
# not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
# Cambridge, MA 02139, USA.
|
||||
|
||||
subdir := elf
|
||||
subdir := elf
|
||||
|
||||
headers := elf.h # libelf.h
|
||||
headers := elf.h libelf.h link.h dlfcn.h
|
||||
routines := init-first
|
||||
|
||||
extra-libs = libelf libdl
|
||||
libelf-routines := elf_hash
|
||||
libdl-routines := dlopen dlclose dlsym dlerror
|
||||
libdl-inhibit-o = $(filter-out .so,$(object-suffixes)) # Build only shared.
|
||||
|
||||
rtld-routines := rtld $(addprefix dl-,minimal load lookup object reloc \
|
||||
runtime sysdep error init fini)
|
||||
distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h \
|
||||
soinit.c sofini.c ldd.sh.in linux-compat.c
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
extra-objs = $(rtld-routines:=.so) soinit.so sofini.so
|
||||
generated = librtld.so
|
||||
install-others = $(slibdir)/$(rtld-installed-name)
|
||||
install-bin = ldd
|
||||
|
||||
ifneq (,$(filter linux%,$(config-os)))
|
||||
extra-objs += linux-compat.so
|
||||
install-others += $(slibdir)/ld-linux.so.1
|
||||
endif
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
|
||||
# Link together the dynamic linker into a single relocatable object.
|
||||
# We use this to produce both the ABI-compliant and Linux-compatible
|
||||
# dynamic linker shared objects below.
|
||||
$(objpfx)librtld.so: $(rtld-routines:%=$(objpfx)%.so) \
|
||||
$(patsubst %,$(common-objpfx)lib%_pic.a,\
|
||||
elf c $(LDLIBS-c.so:-l%=%))
|
||||
$(LINK.o) -nostdlib -nostartfiles -r -o $@ \
|
||||
'-Wl,-(' $^ -lgcc '-Wl,-)'
|
||||
|
||||
$(objpfx)ld.so $(objpfx)ld-linux.so.1: $(objpfx)librtld.so
|
||||
$(LINK.o) -nostdlib -nostartfiles -shared -o $@ \
|
||||
-Wl,-rpath=$(default-rpath) $^
|
||||
|
||||
# The Linux-compatible dynamic linker shared object is just the same
|
||||
# with one object file of compatibility initialization code added.
|
||||
$(objpfx)ld-linux.so.1: $(objpfx)linux-compat.so
|
||||
|
||||
|
||||
$(objpfx)libdl.so: $(objpfx)libdl_pic.a $(common-objpfx)libc.so $(objpfx)ld.so
|
||||
$(patsubst %/,cd %;,$(objpfx)) \
|
||||
$(LINK.o) -shared -o $(@:$(objpfx)%=%) \
|
||||
$(LDFLAGS.so) $(LDFLAGS-dl.so) \
|
||||
-Wl,--whole-archive $(^:$(objpfx)%=%)
|
||||
|
||||
$(slibdir)/$(rtld-installed-name): $(objpfx)ld.so; $(do-install-program)
|
||||
$(slibdir)/ld-linux.so.1: $(objpfx)ld-linux.so.1; $(do-install-program)
|
||||
|
||||
$(objpfx)ldd: ldd.sh.in
|
||||
sed 's%@RTLD@%$(libdir)/$(rtld-installed-name)%g' < $< > $@.new
|
||||
chmod 555 $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Error handling for runtime dynamic linker.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <link.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
static jmp_buf catch_env;
|
||||
static const char *signalled_errstring, *signalled_objname;
|
||||
|
||||
void
|
||||
_dl_signal_error (int errcode,
|
||||
const char *objname,
|
||||
const char *errstring)
|
||||
{
|
||||
signalled_errstring = errstring ?: "DYNAMIC LINKER BUG!!!";
|
||||
signalled_objname = objname;
|
||||
longjmp (catch_env, errcode ?: -1);
|
||||
}
|
||||
|
||||
int
|
||||
_dl_catch_error (const char **errstring,
|
||||
const char **objname,
|
||||
void (*operate) (void))
|
||||
{
|
||||
int errcode;
|
||||
|
||||
signalled_errstring = signalled_objname = NULL;
|
||||
errcode = setjmp (catch_env);
|
||||
if (errcode == 0)
|
||||
{
|
||||
(*operate) ();
|
||||
*errstring = *objname = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We get here only if we longjmp'd out of OPERATE. */
|
||||
*errstring = signalled_errstring;
|
||||
*objname = signalled_objname;
|
||||
return errcode == -1 ? 0 : errcode;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Call the termination functions of loaded shared objects.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
|
||||
void
|
||||
_dl_fini (void)
|
||||
{
|
||||
struct link_map *l;
|
||||
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (l->l_init_called && l->l_info[DT_FINI])
|
||||
(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Return the next shared object initializer function not yet run.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <link.h>
|
||||
|
||||
|
||||
Elf32_Addr
|
||||
_dl_init_next (void)
|
||||
{
|
||||
struct link_map *l;
|
||||
Elf32_Addr init;
|
||||
|
||||
Elf32_Addr next_init (struct link_map *l)
|
||||
{
|
||||
if (l->l_init_called)
|
||||
/* This object is all done. */
|
||||
return 0;
|
||||
if (l->l_init_running)
|
||||
{
|
||||
/* This object's initializer was just running.
|
||||
Now mark it as having run, so this object
|
||||
will be skipped in the future. */
|
||||
l->l_init_called = 1;
|
||||
l->l_init_running = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l->l_info[DT_NEEDED])
|
||||
{
|
||||
/* Find each dependency in order, and see if it
|
||||
needs to run an initializer. */
|
||||
const char *strtab
|
||||
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
const Elf32_Dyn *d;
|
||||
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
{
|
||||
struct link_map *needed
|
||||
= _dl_map_object (l, strtab + d->d_un.d_val);
|
||||
Elf32_Addr init;
|
||||
--needed->l_opencount;
|
||||
init = next_init (needed); /* Recurse on this dependency. */
|
||||
if (init != 0)
|
||||
return init;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->l_info[DT_INIT] &&
|
||||
!(l->l_name[0] == '\0' && l->l_type == lt_executable))
|
||||
{
|
||||
/* Run this object's initializer. */
|
||||
l->l_init_running = 1;
|
||||
return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
|
||||
}
|
||||
|
||||
/* No initializer for this object.
|
||||
Mark it so we will skip it in the future. */
|
||||
l->l_init_called = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look for the first initializer not yet called. */
|
||||
l = _dl_loaded;
|
||||
do
|
||||
{
|
||||
init = next_init (l);
|
||||
l = l->l_next;
|
||||
}
|
||||
while (init == 0 && l);
|
||||
|
||||
return init;
|
||||
}
|
||||
+453
@@ -0,0 +1,453 @@
|
||||
/* _dl_map_object -- Map in a shared object's segments from the file.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "dynamic-link.h"
|
||||
|
||||
|
||||
/* On some systems, no flag bits are given to specify file mapping. */
|
||||
#ifndef MAP_FILE
|
||||
#define MAP_FILE 0
|
||||
#endif
|
||||
|
||||
/* The right way to map in the shared library files is MAP_COPY, which
|
||||
makes a virtual copy of the data at the time of the mmap call; this
|
||||
guarantees the mapped pages will be consistent even if the file is
|
||||
overwritten. Some losing VM systems like Linux's lack MAP_COPY. All we
|
||||
get is MAP_PRIVATE, which copies each page when it is modified; this
|
||||
means if the file is overwritten, we may at some point get some pages
|
||||
from the new version after starting with pages from the old version. */
|
||||
#ifndef MAP_COPY
|
||||
#define MAP_COPY MAP_PRIVATE
|
||||
#endif
|
||||
|
||||
|
||||
#include <endian.h>
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define byteorder ELFDATA2MSB
|
||||
#define byteorder_name "big-endian"
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define byteorder ELFDATA2LSB
|
||||
#define byteorder_name "little-endian"
|
||||
#else
|
||||
#error "Unknown BYTE_ORDER " BYTE_ORDER
|
||||
#define byteorder ELFDATANONE
|
||||
#endif
|
||||
|
||||
#define STRING(x) #x
|
||||
|
||||
int _dl_zerofd = -1;
|
||||
|
||||
|
||||
/* Try to open NAME in one of the directories in DIRPATH.
|
||||
Return the fd, or -1. If successful, fill in *REALNAME
|
||||
with the malloc'd full directory name. */
|
||||
|
||||
static int
|
||||
open_path (const char *name, size_t namelen,
|
||||
const char *dirpath,
|
||||
char **realname)
|
||||
{
|
||||
char *buf;
|
||||
const char *p;
|
||||
int fd;
|
||||
|
||||
p = dirpath;
|
||||
if (p == NULL || *p == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = alloca (strlen (dirpath) + 1 + namelen);
|
||||
do
|
||||
{
|
||||
dirpath = p;
|
||||
p = strpbrk (dirpath, ":;");
|
||||
if (p == NULL)
|
||||
p = strchr (dirpath, '\0');
|
||||
|
||||
if (p == dirpath)
|
||||
/* Two adjacent colons, or a colon at the beginning or the end of
|
||||
the path means to search the current directory. */
|
||||
(void) memcpy (buf, name, namelen);
|
||||
else
|
||||
{
|
||||
/* Construct the pathname to try. */
|
||||
(void) memcpy (buf, dirpath, p - dirpath);
|
||||
buf[p - dirpath] = '/';
|
||||
(void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
|
||||
}
|
||||
|
||||
fd = open (buf, O_RDONLY);
|
||||
if (fd != -1)
|
||||
{
|
||||
*realname = strdup (buf);
|
||||
return fd;
|
||||
}
|
||||
if (errno != ENOENT && errno != EACCES)
|
||||
/* The file exists and is readable, but something went wrong. */
|
||||
return -1;
|
||||
}
|
||||
while (*p++ != '\0');
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Map in the shared object file NAME. */
|
||||
|
||||
struct link_map *
|
||||
_dl_map_object (struct link_map *loader, const char *name)
|
||||
{
|
||||
int fd;
|
||||
char *realname;
|
||||
struct link_map *l;
|
||||
|
||||
/* Look for this name among those already loaded. */
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (! strcmp (name, l->l_libname))
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
++l->l_opencount;
|
||||
return l;
|
||||
}
|
||||
|
||||
if (strchr (name, '/') == NULL)
|
||||
{
|
||||
/* Search for NAME in several places. */
|
||||
|
||||
size_t namelen = strlen (name) + 1;
|
||||
|
||||
inline void trypath (const char *dirpath)
|
||||
{
|
||||
fd = open_path (name, namelen, dirpath, &realname);
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
if (loader && loader->l_info[DT_RPATH])
|
||||
trypath ((const char *) (loader->l_addr +
|
||||
loader->l_info[DT_STRTAB]->d_un.d_ptr +
|
||||
loader->l_info[DT_RPATH]->d_un.d_val));
|
||||
if (fd == -1 && ! _dl_secure)
|
||||
trypath (getenv ("LD_LIBRARY_PATH"));
|
||||
if (fd == -1)
|
||||
{
|
||||
extern const char *_dl_rpath; /* Set in rtld.c. */
|
||||
trypath (_dl_rpath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open (name, O_RDONLY);
|
||||
if (fd != -1)
|
||||
realname = strdup (name);
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
_dl_signal_error (errno, name, "cannot open shared object file");
|
||||
|
||||
return _dl_map_object_from_fd (name, fd, realname);
|
||||
}
|
||||
|
||||
|
||||
/* Map in the shared object NAME, actually located in REALNAME, and already
|
||||
opened on FD. */
|
||||
|
||||
struct link_map *
|
||||
_dl_map_object_from_fd (const char *name, int fd, char *realname)
|
||||
{
|
||||
struct link_map *l = NULL;
|
||||
const size_t pagesize = getpagesize ();
|
||||
void *file_mapping = NULL;
|
||||
size_t mapping_size = 0;
|
||||
|
||||
#define LOSE(s) lose (0, (s))
|
||||
void lose (int code, const char *msg)
|
||||
{
|
||||
(void) close (fd);
|
||||
if (file_mapping)
|
||||
munmap (file_mapping, mapping_size);
|
||||
_dl_signal_error (code, l ? l->l_name : name, msg);
|
||||
}
|
||||
|
||||
inline caddr_t map_segment (Elf32_Addr mapstart, size_t len,
|
||||
int prot, int fixed, off_t offset)
|
||||
{
|
||||
caddr_t mapat = mmap ((caddr_t) mapstart, len, prot,
|
||||
fixed|MAP_COPY|MAP_FILE,
|
||||
fd, offset);
|
||||
if (mapat == (caddr_t) -1)
|
||||
lose (errno, "failed to map segment from shared object");
|
||||
return mapat;
|
||||
}
|
||||
|
||||
/* Make sure LOCATION is mapped in. */
|
||||
void *map (off_t location, size_t size)
|
||||
{
|
||||
if ((off_t) mapping_size <= location + (off_t) size)
|
||||
{
|
||||
void *result;
|
||||
if (file_mapping)
|
||||
munmap (file_mapping, mapping_size);
|
||||
mapping_size = (location + size + 1 + pagesize - 1);
|
||||
mapping_size &= ~(pagesize - 1);
|
||||
result = mmap (file_mapping, mapping_size, PROT_READ,
|
||||
MAP_COPY|MAP_FILE, fd, 0);
|
||||
if (result == (void *) -1)
|
||||
lose (errno, "cannot map file data");
|
||||
file_mapping = result;
|
||||
}
|
||||
return file_mapping + location;
|
||||
}
|
||||
|
||||
const Elf32_Ehdr *header;
|
||||
const Elf32_Phdr *phdr;
|
||||
const Elf32_Phdr *ph;
|
||||
int type;
|
||||
|
||||
/* Look again to see if the real name matched another already loaded. */
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (! strcmp (realname, l->l_name))
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
close (fd);
|
||||
free (realname);
|
||||
++l->l_opencount;
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Map in the first page to read the header. */
|
||||
header = map (0, sizeof *header);
|
||||
|
||||
/* Check the header for basic validity. */
|
||||
if (*(Elf32_Word *) &header->e_ident !=
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
((ELFMAG0 << (EI_MAG0 * 8)) |
|
||||
(ELFMAG1 << (EI_MAG1 * 8)) |
|
||||
(ELFMAG2 << (EI_MAG2 * 8)) |
|
||||
(ELFMAG3 << (EI_MAG3 * 8)))
|
||||
#else
|
||||
((ELFMAG0 << (EI_MAG3 * 8)) |
|
||||
(ELFMAG1 << (EI_MAG2 * 8)) |
|
||||
(ELFMAG2 << (EI_MAG1 * 8)) |
|
||||
(ELFMAG3 << (EI_MAG0 * 8)))
|
||||
#endif
|
||||
)
|
||||
LOSE ("invalid ELF header");
|
||||
if (header->e_ident[EI_CLASS] != ELFCLASS32)
|
||||
LOSE ("ELF file class not 32-bit");
|
||||
if (header->e_ident[EI_DATA] != byteorder)
|
||||
LOSE ("ELF file data encoding not " byteorder_name);
|
||||
if (header->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
LOSE ("ELF file version ident not " STRING(EV_CURRENT));
|
||||
if (header->e_version != EV_CURRENT)
|
||||
LOSE ("ELF file version not " STRING(EV_CURRENT));
|
||||
if (! elf_machine_matches_host (header->e_machine))
|
||||
LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);
|
||||
if (header->e_phentsize != sizeof (Elf32_Phdr))
|
||||
LOSE ("ELF file's phentsize not the expected size");
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, lt_loaded);
|
||||
l->l_opencount = 1;
|
||||
|
||||
if (_dl_zerofd == -1)
|
||||
{
|
||||
_dl_zerofd = _dl_sysdep_open_zero_fill ();
|
||||
if (_dl_zerofd == -1)
|
||||
_dl_signal_error (errno, NULL, "cannot open zero fill device");
|
||||
}
|
||||
|
||||
/* Extract the remaining details we need from the ELF header
|
||||
and then map in the program header table. */
|
||||
l->l_entry = header->e_entry;
|
||||
type = header->e_type;
|
||||
l->l_phnum = header->e_phnum;
|
||||
phdr = map (header->e_phoff, l->l_phnum * sizeof (Elf32_Phdr));
|
||||
|
||||
{
|
||||
/* Scan the program header table, collecting its load commands. */
|
||||
struct loadcmd
|
||||
{
|
||||
Elf32_Addr mapstart, mapend, dataend, allocend;
|
||||
off_t mapoff;
|
||||
int prot;
|
||||
} loadcmds[l->l_phnum], *c;
|
||||
size_t nloadcmds = 0;
|
||||
|
||||
l->l_ld = 0;
|
||||
l->l_phdr = 0;
|
||||
l->l_addr = 0;
|
||||
for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
|
||||
switch (ph->p_type)
|
||||
{
|
||||
/* These entries tell us where to find things once the file's
|
||||
segments are mapped in. We record the addresses it says
|
||||
verbatim, and later correct for the run-time load address. */
|
||||
case PT_DYNAMIC:
|
||||
l->l_ld = (void *) ph->p_vaddr;
|
||||
break;
|
||||
case PT_PHDR:
|
||||
l->l_phdr = (void *) ph->p_vaddr;
|
||||
break;
|
||||
|
||||
case PT_LOAD:
|
||||
/* A load command tells us to map in part of the file.
|
||||
We record the load commands and process them all later. */
|
||||
if (ph->p_align % pagesize != 0)
|
||||
LOSE ("ELF load command alignment not page-aligned");
|
||||
if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
|
||||
LOSE ("ELF load command address/offset not properly aligned");
|
||||
{
|
||||
struct loadcmd *c = &loadcmds[nloadcmds++];
|
||||
c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);
|
||||
c->mapend = ((ph->p_vaddr + ph->p_filesz + pagesize - 1)
|
||||
& ~(pagesize - 1));
|
||||
c->dataend = ph->p_vaddr + ph->p_filesz;
|
||||
c->allocend = ph->p_vaddr + ph->p_memsz;
|
||||
c->mapoff = ph->p_offset & ~(ph->p_align - 1);
|
||||
c->prot = 0;
|
||||
if (ph->p_flags & PF_R)
|
||||
c->prot |= PROT_READ;
|
||||
if (ph->p_flags & PF_W)
|
||||
c->prot |= PROT_WRITE;
|
||||
if (ph->p_flags & PF_X)
|
||||
c->prot |= PROT_EXEC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are done reading the file's headers now. Unmap them. */
|
||||
munmap (file_mapping, mapping_size);
|
||||
|
||||
/* Now process the load commands and map segments into memory. */
|
||||
c = loadcmds;
|
||||
|
||||
if (type == ET_DYN || type == ET_REL)
|
||||
{
|
||||
/* This is a position-independent shared object. We can let the
|
||||
kernel map it anywhere it likes, but we must have space for all
|
||||
the segments in their specified positions relative to the first.
|
||||
So we map the first segment without MAP_FIXED, but with its
|
||||
extent increased to cover all the segments. Then we remove
|
||||
access from excess portion, and there is known sufficient space
|
||||
there to remap from the later segments. */
|
||||
caddr_t mapat;
|
||||
mapat = map_segment (c->mapstart,
|
||||
loadcmds[nloadcmds - 1].allocend - c->mapstart,
|
||||
c->prot, 0, c->mapoff);
|
||||
l->l_addr = (Elf32_Addr) mapat - c->mapstart;
|
||||
|
||||
/* Change protection on the excess portion to disallow all access;
|
||||
the portions we do not remap later will be inaccessible as if
|
||||
unallocated. Then jump into the normal segment-mapping loop to
|
||||
handle the portion of the segment past the end of the file
|
||||
mapping. */
|
||||
mprotect (mapat + c->mapend,
|
||||
loadcmds[nloadcmds - 1].allocend - c->mapend,
|
||||
0);
|
||||
goto postmap;
|
||||
}
|
||||
|
||||
while (c < &loadcmds[nloadcmds])
|
||||
{
|
||||
if (c->mapend > c->mapstart)
|
||||
/* Map the segment contents from the file. */
|
||||
map_segment (l->l_addr + c->mapstart, c->mapend - c->mapstart,
|
||||
c->prot, MAP_FIXED, c->mapoff);
|
||||
|
||||
postmap:
|
||||
if (c->allocend > c->dataend)
|
||||
{
|
||||
/* Extra zero pages should appear at the end of this segment,
|
||||
after the data mapped from the file. */
|
||||
Elf32_Addr zero, zeroend, zeropage;
|
||||
|
||||
zero = l->l_addr + c->dataend;
|
||||
zeroend = l->l_addr + c->allocend;
|
||||
zeropage = (zero + pagesize - 1) & ~(pagesize - 1);
|
||||
|
||||
if (zeroend < zeropage)
|
||||
/* All the extra data is in the last page of the segment.
|
||||
We can just zero it. */
|
||||
zeropage = zeroend;
|
||||
|
||||
if (zeropage > zero)
|
||||
{
|
||||
/* Zero the final part of the last page of the segment. */
|
||||
if ((c->prot & PROT_WRITE) == 0)
|
||||
{
|
||||
/* Dag nab it. */
|
||||
if (mprotect ((caddr_t) (zero & ~(pagesize - 1)),
|
||||
pagesize, c->prot|PROT_WRITE) < 0)
|
||||
lose (errno, "cannot change memory protections");
|
||||
}
|
||||
memset ((void *) zero, 0, zeropage - zero);
|
||||
if ((c->prot & PROT_WRITE) == 0)
|
||||
mprotect ((caddr_t) (zero & ~(pagesize - 1)),
|
||||
pagesize, c->prot);
|
||||
}
|
||||
|
||||
if (zeroend > zeropage)
|
||||
{
|
||||
/* Map the remaining zero pages in from the zero fill FD. */
|
||||
caddr_t mapat;
|
||||
mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_FIXED,
|
||||
_dl_zerofd, 0);
|
||||
if (mapat == (caddr_t) -1)
|
||||
lose (errno, "cannot map zero-fill pages");
|
||||
}
|
||||
}
|
||||
|
||||
++c;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ET_EXEC)
|
||||
l->l_type = lt_executable;
|
||||
|
||||
if (l->l_ld == 0)
|
||||
{
|
||||
if (type == ET_DYN)
|
||||
LOSE ("object file has no dynamic section");
|
||||
}
|
||||
else
|
||||
(Elf32_Addr) l->l_ld += l->l_addr;
|
||||
|
||||
if (l->l_phdr == 0)
|
||||
l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
|
||||
(Elf32_Addr) l->l_phdr += l->l_addr;
|
||||
|
||||
elf_get_dynamic_info (l->l_ld, l->l_info);
|
||||
if (l->l_info[DT_HASH])
|
||||
_dl_setup_hash (l);
|
||||
|
||||
return l;
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/* Look up a symbol in the loaded objects.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <libelf.h>
|
||||
#include <link.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* Search loaded objects' symbol tables for a definition of
|
||||
the symbol UNDEF_NAME. If NOSELF is nonzero, then *REF
|
||||
cannot satisfy the reference itself; some different binding
|
||||
must be found. */
|
||||
|
||||
Elf32_Addr
|
||||
_dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
|
||||
struct link_map *symbol_scope,
|
||||
const char *reference_name,
|
||||
int noself)
|
||||
{
|
||||
unsigned long int hash = elf_hash (undef_name);
|
||||
struct link_map *map;
|
||||
struct
|
||||
{
|
||||
Elf32_Addr a;
|
||||
const Elf32_Sym *s;
|
||||
} weak_value = { 0, NULL };
|
||||
|
||||
/* Search the relevant loaded objects for a definition. */
|
||||
for (map = symbol_scope; map; map = map->l_next)
|
||||
{
|
||||
const Elf32_Sym *symtab;
|
||||
const char *strtab;
|
||||
Elf32_Word symidx;
|
||||
|
||||
symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
|
||||
strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
/* Search the appropriate hash bucket in this object's symbol table
|
||||
for a definition for the same symbol name. */
|
||||
for (symidx = map->l_buckets[hash % map->l_nbuckets];
|
||||
symidx != STN_UNDEF;
|
||||
symidx = map->l_chain[symidx])
|
||||
{
|
||||
const Elf32_Sym *sym = &symtab[symidx];
|
||||
|
||||
if (sym->st_value == 0 || /* No value. */
|
||||
sym->st_shndx == SHN_UNDEF || /* PLT entry. */
|
||||
(noself && sym == *ref)) /* The reference can't define it. */
|
||||
continue;
|
||||
|
||||
switch (ELF32_ST_TYPE (sym->st_info))
|
||||
{
|
||||
case STT_NOTYPE:
|
||||
case STT_FUNC:
|
||||
case STT_OBJECT:
|
||||
break;
|
||||
default:
|
||||
/* Not a code/data definition. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
|
||||
/* Not the symbol we are looking for. */
|
||||
continue;
|
||||
|
||||
switch (ELF32_ST_BIND (sym->st_info))
|
||||
{
|
||||
case STB_GLOBAL:
|
||||
/* Global definition. Just what we need. */
|
||||
*ref = sym;
|
||||
return map->l_addr;
|
||||
case STB_WEAK:
|
||||
/* Weak definition. Use this value if we don't find another. */
|
||||
if (! weak_value.s)
|
||||
{
|
||||
weak_value.s = sym;
|
||||
weak_value.a = map->l_addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Local symbols are ignored. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK)
|
||||
{
|
||||
const char msg[] = "undefined symbol: ";
|
||||
char buf[sizeof msg + strlen (undef_name)];
|
||||
memcpy (buf, msg, sizeof msg - 1);
|
||||
memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg + 1);
|
||||
_dl_signal_error (0, reference_name, buf);
|
||||
}
|
||||
|
||||
*ref = weak_value.s;
|
||||
return weak_value.a;
|
||||
}
|
||||
|
||||
|
||||
/* Cache the location of MAP's hash table. */
|
||||
|
||||
void
|
||||
_dl_setup_hash (struct link_map *map)
|
||||
{
|
||||
Elf32_Word *hash = (void *) map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr;
|
||||
Elf32_Word nchain;
|
||||
map->l_nbuckets = *hash++;
|
||||
nchain = *hash++;
|
||||
map->l_buckets = hash;
|
||||
hash += map->l_nbuckets;
|
||||
map->l_chain = hash;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/* Minimal replacements for basic facilities used in the dynamic linker.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <link.h>
|
||||
#include "../stdio-common/_itoa.h"
|
||||
|
||||
/* Minimal `malloc' allocator for use while loading shared libraries.
|
||||
Only small blocks are allocated, and none are ever freed. */
|
||||
|
||||
static void *alloc_ptr, *alloc_end, *alloc_last_block;
|
||||
|
||||
void *
|
||||
malloc (size_t n)
|
||||
{
|
||||
extern int _dl_zerofd;
|
||||
static size_t pagesize;
|
||||
|
||||
if (pagesize == 0)
|
||||
pagesize = __getpagesize ();
|
||||
|
||||
if (_dl_zerofd == -1)
|
||||
_dl_zerofd = _dl_sysdep_open_zero_fill ();
|
||||
|
||||
if (alloc_end == 0)
|
||||
{
|
||||
/* Consume any unused space in the last page of our data segment. */
|
||||
extern int _end;
|
||||
alloc_ptr = &_end;
|
||||
alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) + pagesize - 1)
|
||||
& ~(pagesize - 1));
|
||||
}
|
||||
|
||||
/* Make sure the allocation pointer is ideally aligned. */
|
||||
alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + sizeof (double) - 1)
|
||||
& ~(sizeof (double) - 1));
|
||||
|
||||
if (alloc_ptr + n >= alloc_end)
|
||||
{
|
||||
/* Insufficient space left; allocate another page. */
|
||||
caddr_t page;
|
||||
assert (n <= pagesize);
|
||||
page = mmap (0, pagesize, PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
|
||||
assert (page != (caddr_t) -1);
|
||||
if (page != alloc_end)
|
||||
alloc_ptr = page;
|
||||
alloc_end = page + pagesize;
|
||||
}
|
||||
|
||||
alloc_last_block = (void *) alloc_ptr;
|
||||
alloc_ptr += n;
|
||||
return alloc_last_block;
|
||||
}
|
||||
weak_symbol (malloc)
|
||||
|
||||
/* This will rarely be called. */
|
||||
void
|
||||
free (void *ptr)
|
||||
{
|
||||
/* We can free only the last block allocated. */
|
||||
if (ptr == alloc_last_block)
|
||||
alloc_ptr = alloc_last_block;
|
||||
}
|
||||
weak_symbol (free)
|
||||
|
||||
/* This is never called. */
|
||||
void *
|
||||
realloc (void *ptr, size_t n)
|
||||
{ ptr += n; abort (); }
|
||||
weak_symbol (realloc)
|
||||
|
||||
/* Avoid signal frobnication in setjmp/longjmp. Keeps things smaller. */
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
int __sigjmp_save (sigjmp_buf env, int savemask)
|
||||
{ env[0].__mask_was_saved = savemask; return 0; }
|
||||
weak_symbol (__sigjmp_save)
|
||||
|
||||
void
|
||||
longjmp (jmp_buf env, int val) { __longjmp (env[0].__jmpbuf, val); }
|
||||
weak_symbol (longjmp)
|
||||
|
||||
|
||||
/* Define our own stub for the localization function used by strerror.
|
||||
English-only in the dynamic linker keeps it smaller. */
|
||||
|
||||
char *
|
||||
__dgettext (const char *domainname, const char *msgid)
|
||||
{
|
||||
assert (domainname == _libc_intl_domainname);
|
||||
return (char *) msgid;
|
||||
}
|
||||
weak_symbol (__dgettext)
|
||||
weak_alias (__dgettext, dgettext)
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/* Define (weakly) our own assert failure function which doesn't use stdio.
|
||||
If we are linked into the user program (-ldl), the normal __assert_fail
|
||||
defn can override this one. */
|
||||
|
||||
void
|
||||
__assert_fail (const char *assertion,
|
||||
const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
char buf[64];
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
_dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
|
||||
file, ": ", _itoa (line, buf + sizeof buf - 1, 10, 0),
|
||||
": ", function ?: "", function ? ": " : "",
|
||||
"Assertion `", assertion, "' failed!\n",
|
||||
NULL);
|
||||
|
||||
}
|
||||
weak_symbol (__assert_fail)
|
||||
|
||||
void
|
||||
__assert_perror_fail (int errnum,
|
||||
const char *file, unsigned int line,
|
||||
const char *function)
|
||||
{
|
||||
char buf[64];
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
_dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
|
||||
file, ": ", _itoa (line, buf + sizeof buf - 1, 10, 0),
|
||||
": ", function ?: "", function ? ": " : "",
|
||||
"Unexpected error: ", strerror (errnum), "\n", NULL);
|
||||
|
||||
}
|
||||
weak_symbol (__assert_perror_fail)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Storage management for the chain of loaded shared objects.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/* List of objects currently loaded. */
|
||||
struct link_map *_dl_loaded;
|
||||
|
||||
/* Tail of that list which were loaded at startup. */
|
||||
struct link_map *_dl_startup_loaded;
|
||||
|
||||
/* Allocate a `struct link_map' for a new object being loaded,
|
||||
and enter it into the _dl_loaded list. */
|
||||
|
||||
struct link_map *
|
||||
_dl_new_object (char *realname, const char *libname, int type)
|
||||
{
|
||||
struct link_map *new = malloc (sizeof *new);
|
||||
if (! new)
|
||||
_dl_signal_error (ENOMEM, libname,
|
||||
"cannot allocate shared object descriptor");
|
||||
|
||||
memset (new, 0, sizeof *new);
|
||||
new->l_name = realname;
|
||||
new->l_libname = libname;
|
||||
new->l_type = type;
|
||||
|
||||
if (_dl_loaded == NULL)
|
||||
{
|
||||
new->l_prev = new->l_next = NULL;
|
||||
_dl_loaded = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct link_map *l = _dl_loaded;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
new->l_prev = l;
|
||||
new->l_next = NULL;
|
||||
l->l_next = new;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/* Relocate a shared object and resolve its references to other loaded objects.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "dynamic-link.h"
|
||||
|
||||
|
||||
void
|
||||
_dl_relocate_object (struct link_map *l, int lazy)
|
||||
{
|
||||
const size_t pagesize = getpagesize ();
|
||||
|
||||
if (l->l_relocated)
|
||||
return;
|
||||
|
||||
if (l->l_info[DT_TEXTREL])
|
||||
{
|
||||
/* Bletch. We must make read-only segments writable
|
||||
long enough to relocate them. */
|
||||
const Elf32_Phdr *ph;
|
||||
for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
|
||||
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
|
||||
{
|
||||
caddr_t mapstart = ((caddr_t) l->l_addr +
|
||||
(ph->p_vaddr & ~(pagesize - 1)));
|
||||
caddr_t mapend = ((caddr_t) l->l_addr +
|
||||
((ph->p_vaddr + ph->p_memsz + pagesize - 1)
|
||||
& ~(pagesize - 1)));
|
||||
if (mprotect (mapstart, mapend - mapstart,
|
||||
PROT_READ|PROT_WRITE) < 0)
|
||||
_dl_signal_error (errno, l->l_name,
|
||||
"cannot make segment writable for relocation");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct link_map *real_next, *scope;
|
||||
|
||||
const char *strtab
|
||||
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
|
||||
Elf32_Addr resolve (const Elf32_Sym **ref, Elf32_Addr r_offset)
|
||||
{
|
||||
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
|
||||
l->l_name, (*ref)->st_value == r_offset);
|
||||
}
|
||||
|
||||
real_next = l->l_next;
|
||||
if (l->l_info[DT_SYMBOLIC])
|
||||
{
|
||||
if (l->l_prev)
|
||||
l->l_prev->l_next = real_next;
|
||||
l->l_next = _dl_loaded;
|
||||
scope = l;
|
||||
}
|
||||
else
|
||||
scope = _dl_loaded;
|
||||
|
||||
if (l->l_type == lt_interpreter)
|
||||
/* We cannot be lazy when relocating the dynamic linker itself. It
|
||||
was previously relocated eagerly (allowing us to be running now),
|
||||
and needs always to be fully relocated so it can run without the
|
||||
aid of run-time fixups (because it's the one to do them), so we
|
||||
must always re-relocate its PLT eagerly. */
|
||||
lazy = 0;
|
||||
|
||||
ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
|
||||
|
||||
/* Restore list frobnication done above for DT_SYMBOLIC. */
|
||||
l->l_next = real_next;
|
||||
if (l->l_prev)
|
||||
l->l_prev->l_next = l;
|
||||
}
|
||||
|
||||
/* Set up the PLT so its unrelocated entries will
|
||||
jump to _dl_runtime_resolve, which will relocate them. */
|
||||
elf_machine_runtime_setup (l, lazy);
|
||||
|
||||
l->l_relocated = 1;
|
||||
|
||||
if (l->l_info[DT_TEXTREL])
|
||||
{
|
||||
/* Undo the protection change we made before relocating. */
|
||||
const Elf32_Phdr *ph;
|
||||
for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
|
||||
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
|
||||
{
|
||||
caddr_t mapstart = ((caddr_t) l->l_addr +
|
||||
(ph->p_vaddr & ~(pagesize - 1)));
|
||||
caddr_t mapend = ((caddr_t) l->l_addr +
|
||||
((ph->p_vaddr + ph->p_memsz + pagesize - 1)
|
||||
& ~(pagesize - 1)));
|
||||
int prot = 0;
|
||||
if (ph->p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (ph->p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
if (mprotect (mapstart, mapend - mapstart, prot) < 0)
|
||||
_dl_signal_error (errno, l->l_name,
|
||||
"can't restore segment prot after reloc");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* dlclose -- Close a handle opened by `dlopen'.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
#define LOSE(s) _dl_signal_error (0, map->l_name, s)
|
||||
|
||||
int
|
||||
dlclose (void *handle)
|
||||
{
|
||||
void doit (void)
|
||||
{
|
||||
struct link_map *map = handle;
|
||||
|
||||
if (map->l_opencount == 0)
|
||||
LOSE ("shared object not open");
|
||||
|
||||
/* Decrement the reference count. */
|
||||
--map->l_opencount;
|
||||
|
||||
if (map->l_opencount == 0 && map->l_type == lt_loaded)
|
||||
{
|
||||
/* That was the last reference, and this was a dlopen-loaded
|
||||
object. We can unmap it. */
|
||||
const Elf32_Phdr *ph;
|
||||
|
||||
if (map->l_info[DT_FINI])
|
||||
/* Call its termination function. */
|
||||
(*(void (*) (void)) ((void *) map->l_addr +
|
||||
map->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
|
||||
if (map->l_info[DT_NEEDED])
|
||||
{
|
||||
/* Also close all the dependencies. */
|
||||
const char *strtab
|
||||
= (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr;
|
||||
const Elf32_Dyn *d;
|
||||
for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
{
|
||||
/* It must already be open, since this one needed it;
|
||||
so dlopen will just find us its `struct link_map'
|
||||
and bump its reference count. */
|
||||
struct link_map *o, *dep
|
||||
= dlopen (strtab + d->d_un.d_val, RTLD_LAZY);
|
||||
--dep->l_opencount; /* Lose the ref from that dlopen. */
|
||||
/* Now we have the handle; we can close it for real. */
|
||||
o = map;
|
||||
map = dep;
|
||||
doit ();
|
||||
map = o;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap the segments. */
|
||||
for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
|
||||
Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
|
||||
+ ph->p_align - 1)
|
||||
& ~(ph->p_align - 1));
|
||||
munmap ((caddr_t) mapstart, mapend - mapstart);
|
||||
}
|
||||
|
||||
/* Finally, unlink the data structure and free it. */
|
||||
map->l_prev->l_next = map->l_next;
|
||||
if (map->l_next)
|
||||
map->l_next->l_prev = map->l_prev;
|
||||
free (map);
|
||||
}
|
||||
}
|
||||
|
||||
return _dlerror_run (doit) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* dlerror -- Return error detail for failing <dlfcn.h> functions.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int last_errcode;
|
||||
static const char *last_errstring;
|
||||
static const char *last_object_name;
|
||||
|
||||
char *
|
||||
dlerror (void)
|
||||
{
|
||||
static char *buf;
|
||||
char *ret;
|
||||
|
||||
if (buf)
|
||||
{
|
||||
free (buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if (! last_errstring)
|
||||
return NULL;
|
||||
|
||||
if (last_errcode == 0 && ! last_object_name)
|
||||
ret = (char *) last_errstring;
|
||||
else if (last_errcode == 0)
|
||||
ret = (asprintf (&buf, "%s: %s", last_object_name, last_errstring) == -1
|
||||
? NULL : buf);
|
||||
else if (! last_object_name)
|
||||
ret = (asprintf (&buf, "%s: %s",
|
||||
last_errstring, strerror (last_errcode)) == -1
|
||||
? NULL : buf);
|
||||
else
|
||||
ret = (asprintf (&buf, "%s: %s: %s",
|
||||
last_object_name, last_errstring,
|
||||
strerror (last_errcode)) == -1
|
||||
? NULL : buf);
|
||||
|
||||
/* Reset the error indicator. */
|
||||
last_errstring = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_dlerror_run (void (*operate) (void))
|
||||
{
|
||||
last_errcode = _dl_catch_error (&last_errstring, &last_object_name,
|
||||
operate);
|
||||
return last_errstring != NULL;
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/* dlfcn.h -- User functions for run-time dynamic loading.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _DLFCN_H
|
||||
#define _DLFCN_H 1
|
||||
|
||||
|
||||
/* Type of the second argument to `dlopen'. */
|
||||
typedef enum
|
||||
{
|
||||
RTLD_LAZY = 1, /* Lazy function call binding. */
|
||||
RTLD_NOW = 2 /* Immediate function call binding. */
|
||||
} dl_open_mode;
|
||||
|
||||
/* Open the shared object FILE and map it in; return a handle that can be
|
||||
passed to `dlsym' to get symbol values from it. */
|
||||
extern void *dlopen (const char *__file, dl_open_mode);
|
||||
|
||||
/* Unmap and close a shared object opened by `dlopen'.
|
||||
The handle cannot be used again after calling `dlclose'. */
|
||||
extern int dlclose (void *__handle);
|
||||
|
||||
/* Find the run-time address in the shared object HANDLE refers to
|
||||
of the symbol called NAME. */
|
||||
extern void *dlsym (void *__handle, const char *__name);
|
||||
|
||||
/* When any of the above functions fails, call this function
|
||||
to return a string describing the error. Each call resets
|
||||
the error string so that a following call returns null. */
|
||||
extern char *dlerror (void);
|
||||
|
||||
|
||||
#endif /* dlfcn.h */
|
||||
@@ -0,0 +1,62 @@
|
||||
/* dlopen -- Load a shared object at run time.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
void *
|
||||
dlopen (const char *file, dl_open_mode mode)
|
||||
{
|
||||
struct link_map *new, *l;
|
||||
|
||||
void doit (void)
|
||||
{
|
||||
Elf32_Addr init;
|
||||
|
||||
new = _dl_map_object (_dl_loaded, file);
|
||||
|
||||
/* Map in any dependencies. */
|
||||
for (l = new; l; l = l->l_next)
|
||||
if (! l->l_deps_loaded)
|
||||
{
|
||||
if (l->l_info[DT_NEEDED])
|
||||
{
|
||||
const char *strtab
|
||||
= (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
|
||||
const Elf32_Dyn *d;
|
||||
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
_dl_map_object (l, strtab + d->d_un.d_val);
|
||||
}
|
||||
l->l_deps_loaded = 1;
|
||||
}
|
||||
|
||||
/* Relocate the objects loaded. */
|
||||
for (l = new; l; l = l->l_next)
|
||||
if (! l->l_relocated)
|
||||
_dl_relocate_object (l, mode == RTLD_LAZY);
|
||||
|
||||
/* Run the initializer functions of new objects. */
|
||||
while (init = _dl_init_next ())
|
||||
(*(void (*) (void)) init) ();
|
||||
}
|
||||
|
||||
return _dlerror_run (doit) ? NULL : new;
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/* dlsym -- Look up a symbol in a shared object loaded by `dlopen'.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
void *
|
||||
dlsym (void *handle, const char *name)
|
||||
{
|
||||
struct link_map *map = handle;
|
||||
struct link_map *real_next;
|
||||
Elf32_Addr loadbase;
|
||||
const Elf32_Sym *ref = NULL;
|
||||
int lose;
|
||||
void doit (void)
|
||||
{
|
||||
loadbase = _dl_lookup_symbol (name, &ref, map, map->l_name, 1);
|
||||
}
|
||||
|
||||
/* Confine the symbol scope to just this map. */
|
||||
real_next = map->l_next;
|
||||
map->l_next = NULL;
|
||||
lose = _dlerror_run (doit);
|
||||
map->l_next = real_next;
|
||||
|
||||
return lose ? NULL : (void *) (loadbase + ref->st_value);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Do relocations for ELF dynamic linking.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
/* This file may be included twice, to define both
|
||||
`elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */
|
||||
|
||||
#ifdef DO_RELA
|
||||
#define elf_dynamic_do_rel elf_dynamic_do_rela
|
||||
#define Elf32_Rel Elf32_Rela
|
||||
#define elf_machine_rel elf_machine_rela
|
||||
#endif
|
||||
|
||||
|
||||
/* Perform the relocations in MAP on the running program image as specified
|
||||
by RELTAG, SZTAG. *RESOLVE is called to resolve symbol values; it
|
||||
modifies its argument pointer to point to the defining symbol, and
|
||||
returns the base load address of the defining object. If LAZY is
|
||||
nonzero, this is the first pass on PLT relocations; they should be set
|
||||
up to call _dl_runtime_resolve, rather than fully resolved now. */
|
||||
|
||||
static inline void
|
||||
elf_dynamic_do_rel (struct link_map *map,
|
||||
int reltag, int sztag,
|
||||
Elf32_Addr (*resolve) (const Elf32_Sym **symbol,
|
||||
Elf32_Addr r_offset),
|
||||
int lazy)
|
||||
{
|
||||
const Elf32_Sym *const symtab
|
||||
= (const Elf32_Sym *) (map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
|
||||
const Elf32_Rel *r
|
||||
= (const Elf32_Rel *) (map->l_addr + map->l_info[reltag]->d_un.d_ptr);
|
||||
const Elf32_Rel *end = &r[map->l_info[sztag]->d_un.d_val / sizeof *r];
|
||||
|
||||
if (lazy)
|
||||
/* Doing lazy PLT relocations; they need very little info. */
|
||||
for (; r < end; ++r)
|
||||
elf_machine_lazy_rel (map, r);
|
||||
else
|
||||
for (; r < end; ++r)
|
||||
{
|
||||
const Elf32_Sym *definer = &symtab[ELF32_R_SYM (r->r_info)];
|
||||
Elf32_Addr loadbase;
|
||||
|
||||
if (ELF32_R_SYM (r->r_info) == STN_UNDEF)
|
||||
loadbase = 0; /* This value will not be consulted. */
|
||||
else if (ELF32_ST_BIND (definer->st_info) == STB_LOCAL)
|
||||
/* Local symbols always refer to the containing object. */
|
||||
loadbase = map->l_addr;
|
||||
else
|
||||
{
|
||||
if (resolve)
|
||||
loadbase = (*resolve) (&definer, r->r_offset);
|
||||
else
|
||||
{
|
||||
assert (definer->st_shndx != SHN_UNDEF);
|
||||
loadbase = map->l_addr;
|
||||
}
|
||||
}
|
||||
elf_machine_rel (map, r, loadbase, definer);
|
||||
}
|
||||
}
|
||||
|
||||
#undef elf_dynamic_do_rel
|
||||
#undef Elf32_Rel
|
||||
#undef elf_machine_rel
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Inline functions for dynamic linking.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <elf.h>
|
||||
#include <dl-machine.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
|
||||
|
||||
static inline void
|
||||
elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM + DT_PROCNUM])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < DT_NUM + DT_PROCNUM; ++i)
|
||||
info[i] = NULL;
|
||||
|
||||
if (! dyn)
|
||||
return;
|
||||
|
||||
while (dyn->d_tag != DT_NULL)
|
||||
{
|
||||
if (dyn->d_tag < DT_NUM)
|
||||
info[dyn->d_tag] = dyn;
|
||||
else if (dyn->d_tag >= DT_LOPROC &&
|
||||
dyn->d_tag < DT_LOPROC + DT_PROCNUM)
|
||||
info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
|
||||
else
|
||||
assert (! "bad dynamic tag");
|
||||
dyn++;
|
||||
}
|
||||
|
||||
if (info[DT_RELA])
|
||||
assert (info[DT_RELAENT]->d_un.d_val == sizeof (Elf32_Rela));
|
||||
if (info[DT_REL])
|
||||
assert (info[DT_RELENT]->d_un.d_val == sizeof (Elf32_Rel));
|
||||
if (info[DT_PLTREL])
|
||||
assert (info[DT_PLTREL]->d_un.d_val == DT_REL ||
|
||||
info[DT_PLTREL]->d_un.d_val == DT_RELA);
|
||||
}
|
||||
|
||||
/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
|
||||
These functions are almost identical, so we use cpp magic to avoid
|
||||
duplicating their code. It cannot be done in a more general function
|
||||
because we must be able to completely inline. */
|
||||
|
||||
#if ! ELF_MACHINE_NO_REL
|
||||
#include "do-rel.h"
|
||||
#define ELF_DYNAMIC_DO_REL(map, lazy, resolve) \
|
||||
if ((map)->l_info[DT_REL]) \
|
||||
elf_dynamic_do_rel ((map), DT_REL, DT_RELSZ, (resolve), 0); \
|
||||
if ((map)->l_info[DT_PLTREL] && \
|
||||
(map)->l_info[DT_PLTREL]->d_un.d_val == DT_REL) \
|
||||
elf_dynamic_do_rel ((map), DT_JMPREL, DT_PLTRELSZ, (resolve), (lazy));
|
||||
#else
|
||||
#define ELF_DYNAMIC_DO_REL(map, lazy, resolve) /* Nothing to do. */
|
||||
#endif
|
||||
|
||||
#if ! ELF_MACHINE_NO_RELA
|
||||
#define DO_RELA
|
||||
#include "do-rel.h"
|
||||
#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) \
|
||||
if ((map)->l_info[DT_RELA]) \
|
||||
elf_dynamic_do_rela ((map), DT_RELA, DT_RELASZ, (resolve), 0); \
|
||||
if ((map)->l_info[DT_PLTREL] && \
|
||||
(map)->l_info[DT_PLTREL]->d_un.d_val == DT_RELA) \
|
||||
elf_dynamic_do_rela ((map), DT_JMPREL, DT_PLTRELSZ, (resolve), (lazy));
|
||||
#else
|
||||
#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) /* Nothing to do. */
|
||||
#endif
|
||||
|
||||
/* This can't just be an inline function because GCC is too dumb
|
||||
to inline functions containing inlines themselves. */
|
||||
#define ELF_DYNAMIC_RELOCATE(map, lazy, resolve) \
|
||||
do { ELF_DYNAMIC_DO_REL ((map), (lazy), (resolve)); \
|
||||
ELF_DYNAMIC_DO_RELA ((map), (lazy), (resolve)); } while (0)
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This file defines standard ELF types, structures, and macros.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
Contributed by Ian Lance Taylor (ian@cygnus.com).
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
@@ -72,6 +72,10 @@ typedef struct
|
||||
#define EI_MAG3 3 /* File identification byte 3 index */
|
||||
#define ELFMAG3 'F' /* Magic number byte 3 */
|
||||
|
||||
/* Conglomeration of the identification bytes, for easy testing as a word. */
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
|
||||
#define EI_CLASS 4 /* File class byte index */
|
||||
#define ELFCLASSNONE 0 /* Invalid class */
|
||||
#define ELFCLASS32 1 /* 32-bit objects */
|
||||
@@ -94,6 +98,7 @@ typedef struct
|
||||
#define ET_EXEC 2 /* Executable file */
|
||||
#define ET_DYN 3 /* Shared object file */
|
||||
#define ET_CORE 4 /* Core file */
|
||||
#define ET_NUM 5 /* Number of defined types. */
|
||||
#define ET_LOPROC 0xff00 /* Processor-specific */
|
||||
#define ET_HIPROC 0xffff /* Processor-specific */
|
||||
|
||||
@@ -108,7 +113,7 @@ typedef struct
|
||||
#define EM_486 6 /* Intel 80486 */
|
||||
#define EM_860 7 /* Intel 80860 */
|
||||
#define EM_MIPS 8 /* MIPS R3000 big-endian */
|
||||
#define EM_S370 9 /* Amdhal */
|
||||
#define EM_S370 9 /* Amdahl */
|
||||
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
|
||||
|
||||
#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */
|
||||
@@ -164,6 +169,7 @@ typedef struct
|
||||
#define SHT_REL 9 /* Relocation entries, no addends */
|
||||
#define SHT_SHLIB 10 /* Reserved */
|
||||
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
|
||||
#define SHT_NUM 12 /* Number of defined types. */
|
||||
#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
|
||||
#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
|
||||
#define SHT_LOUSER 0x80000000 /* Start of application-specific */
|
||||
@@ -188,9 +194,9 @@ typedef struct
|
||||
Elf32_Half st_shndx; /* Section index */
|
||||
} Elf32_Sym;
|
||||
|
||||
/* Special symbol index. */
|
||||
/* Special section index. */
|
||||
|
||||
#define STN_UNDEF 0 /* Undefined symbol */
|
||||
#define SHN_UNDEF 0 /* No section, undefined symbol. */
|
||||
|
||||
/* How to extract and insert information held in the st_info field. */
|
||||
|
||||
@@ -203,6 +209,7 @@ typedef struct
|
||||
#define STB_LOCAL 0 /* Local symbol */
|
||||
#define STB_GLOBAL 1 /* Global symbol */
|
||||
#define STB_WEAK 2 /* Weak symbol */
|
||||
#define STB_NUM 3 /* Number of defined types. */
|
||||
#define STB_LOPROC 13 /* Start of processor-specific */
|
||||
#define STB_HIPROC 15 /* End of processor-specific */
|
||||
|
||||
@@ -213,9 +220,18 @@ typedef struct
|
||||
#define STT_FUNC 2 /* Symbol is a code object */
|
||||
#define STT_SECTION 3 /* Symbol associated with a section */
|
||||
#define STT_FILE 4 /* Symbol's name is file name */
|
||||
#define STT_NUM 5 /* Number of defined types. */
|
||||
#define STT_LOPROC 13 /* Start of processor-specific */
|
||||
#define STT_HIPROC 15 /* End of processor-specific */
|
||||
|
||||
|
||||
/* Symbol table indices are found in the hash buckets and chain table
|
||||
of a symbol hash table section. This special index value indicates
|
||||
the end of a chain, meaning no further symbols are found in that bucket. */
|
||||
|
||||
#define STN_UNDEF 0 /* End of a chain. */
|
||||
|
||||
|
||||
/* Relocation table entry without addend (in section of type SHT_REL). */
|
||||
|
||||
typedef struct
|
||||
@@ -261,6 +277,7 @@ typedef struct {
|
||||
#define PT_NOTE 4 /* Auxiliary information */
|
||||
#define PT_SHLIB 5 /* Reserved */
|
||||
#define PT_PHDR 6 /* Entry for header table itself */
|
||||
#define PT_NUM 7 /* Number of defined types. */
|
||||
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
|
||||
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
|
||||
|
||||
@@ -309,8 +326,10 @@ typedef struct
|
||||
#define DT_DEBUG 21 /* For debugging; unspecified */
|
||||
#define DT_TEXTREL 22 /* Reloc might modify .text */
|
||||
#define DT_JMPREL 23 /* Address of PLT relocs */
|
||||
#define DT_NUM 24 /* Number used */
|
||||
#define DT_LOPROC 0x70000000 /* Start of processor-specific */
|
||||
#define DT_HIPROC 0x7fffffff /* End of processor-specific */
|
||||
#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
|
||||
|
||||
/* Standard 64 bit ELF types. */
|
||||
|
||||
@@ -417,7 +436,7 @@ typedef struct
|
||||
#define AT_NOTELF 10 /* Program is not ELF */
|
||||
#define AT_UID 11 /* Real uid */
|
||||
#define AT_EUID 12 /* Effective uid */
|
||||
#define AT_GID 13 /* Read gid */
|
||||
#define AT_GID 13 /* Real gid */
|
||||
#define AT_EGID 14 /* Effective gid */
|
||||
|
||||
/* Intel 80386 specific definitions. */
|
||||
@@ -536,7 +555,7 @@ typedef struct
|
||||
|
||||
/* Legal values for p_type field of Elf32_Phdr. */
|
||||
|
||||
#define PT_MIPS_REGINFO 0x70000000 /* Regiser usage information */
|
||||
#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
|
||||
|
||||
/* Legal values for d_tag field of Elf32_Dyn. */
|
||||
|
||||
@@ -555,6 +574,7 @@ typedef struct
|
||||
#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
|
||||
#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
|
||||
#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
|
||||
#define DT_MIPS_NUM 0x15
|
||||
|
||||
/* Legal values for DT_MIPS_FLAG Elf32_Dyn entry. */
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This is the `ldd' command, which lists what shared libraries are
|
||||
# used by given dynamically-linked executables. It works by invoking the
|
||||
# run-time dynamic linker as a command and giving it the special `--list'
|
||||
# switch.
|
||||
|
||||
RTLD=@RTLD@
|
||||
|
||||
case $# in
|
||||
0)
|
||||
echo >&2 "Usage: $0 FILE..."
|
||||
exit 1 ;;
|
||||
1)
|
||||
# We don't list the file name when there is only one.
|
||||
case "$1" in
|
||||
/*) file="$1" ;;
|
||||
*) file="./$1" ;;
|
||||
esac
|
||||
exec ${RTLD} --list "$file" && exit 1
|
||||
exit ;;
|
||||
*)
|
||||
set -e # Bail out immediately if ${RTLD} loses on any argument.
|
||||
for file; do
|
||||
echo "${file}:"
|
||||
case "$file" in
|
||||
/*) file="$file" ;;
|
||||
*) file="./$file" ;;
|
||||
esac
|
||||
${RTLD} --list "$file"
|
||||
done
|
||||
esac
|
||||
|
||||
exit 0
|
||||
+10
-5
@@ -107,7 +107,7 @@ typedef struct
|
||||
/* Data descriptor. */
|
||||
typedef struct
|
||||
{
|
||||
Elf_Void *d_buf;
|
||||
void *d_buf;
|
||||
Elf_Type d_type;
|
||||
size_t d_size;
|
||||
off_t d_off; /* Offset into section. */
|
||||
@@ -155,7 +155,7 @@ extern unsigned int elf_flagdata __P ((Elf_Data *__data, Elf_Cmd __cmd,
|
||||
extern unsigned int elf_flagehdr __P ((Elf *__elf, Elf_Cmd __cmd,
|
||||
unsigned int __flags));
|
||||
/* Modify flags affecting the ELF program header. */
|
||||
extern unsigned int elf_flagphdr __P ((Elf *__elf, Elf_Cmd, __cmd
|
||||
extern unsigned int elf_flagphdr __P ((Elf *__elf, Elf_Cmd __cmd,
|
||||
unsigned int __flags));
|
||||
/* Modify flags affecting the given section's data. */
|
||||
extern unsigned int elf_flagscn __P ((Elf_Scn *__scn, Elf_Cmd __cmd,
|
||||
@@ -220,9 +220,14 @@ elf_hash (__const char *__name)
|
||||
__hash = (__hash << 4) + *__name++;
|
||||
__hi = __hash & 0xf0000000;
|
||||
if (__hi != 0)
|
||||
__hash ^= __hi >> 24;
|
||||
hash &= ~__hi;
|
||||
{
|
||||
__hash ^= __hi >> 24;
|
||||
/* The ELF ABI says `hash &= ~hi', but this is equivalent
|
||||
in this case and on some machines one insn instead of two. */
|
||||
__hash ^= __hi;
|
||||
}
|
||||
}
|
||||
return __hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -261,7 +266,7 @@ extern char *elf_strptr __P ((Elf *__elf, size_t __section, size_t __offset));
|
||||
|
||||
/* If CMD is ELF_C_NULL, update ELF's data structures based on any
|
||||
user modifications, and set the ELF_F_DIRTY flag if anything changed.
|
||||
If CMD is ELF_C_WRITE, do that and then write the changes to the file.
|
||||
If CMD is ELF_C_WRITE, do that and then write the changes to the file. */
|
||||
extern off_t elf_update __P ((Elf *__elf, Elf_Cmd __cmd));
|
||||
|
||||
/* Handle ELF version VER. Return the old version handled,
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/* Run-time dynamic linker data structures for loaded ELF shared objects.
|
||||
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _LINK_H
|
||||
#define _LINK_H 1
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
|
||||
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||
details of shared object loading to the debugger. If the executable's
|
||||
dynamic section has a DT_DEBUG element, the run-time linker sets that
|
||||
element's value to the address where this structure can be found. */
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
int r_version; /* Version number for this protocol. */
|
||||
|
||||
struct link_map *r_map; /* Head of the chain of loaded objects. */
|
||||
|
||||
/* This is the address of a function internal to the run-time linker,
|
||||
that will always be called when the linker begins to map in a
|
||||
library or unmap it, and again when the mapping change is complete.
|
||||
The debugger can set a breakpoint at this address if it wants to
|
||||
notice shared object mapping changes. */
|
||||
Elf32_Addr r_brk;
|
||||
enum
|
||||
{
|
||||
/* This state value describes the mapping change taking place when
|
||||
the `r_brk' address is called. */
|
||||
RT_CONSISTENT, /* Mapping change is complete. */
|
||||
RT_ADD, /* Beginning to add a new object. */
|
||||
RT_DELETE, /* Beginning to remove an object mapping. */
|
||||
} r_state;
|
||||
|
||||
Elf32_Addr r_ldbase; /* Base address the linker is loaded at. */
|
||||
};
|
||||
|
||||
/* This symbol refers to the "dynamic structure" in the `.dynamic' section
|
||||
of whatever module refers to `_DYNAMIC'. So, to find its own
|
||||
`struct r_debug', a program could do:
|
||||
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL)
|
||||
if (dyn->d_tag == DT_DEBUG) r_debug = (struct r_debug) dyn->d_un.d_ptr;
|
||||
*/
|
||||
|
||||
extern Elf32_Dyn _DYNAMIC[];
|
||||
|
||||
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
members form a chain of all the shared objects loaded at startup.
|
||||
|
||||
These data structures exist in space used by the run-time dynamic linker;
|
||||
modifying them may have disastrous results. */
|
||||
|
||||
struct link_map
|
||||
{
|
||||
/* These first few members are part of the protocol with the debugger.
|
||||
This is the same format used in SVR4. */
|
||||
|
||||
Elf32_Addr l_addr; /* Base address shared object is loaded at. */
|
||||
char *l_name; /* Absolute file name object was found in. */
|
||||
Elf32_Dyn *l_ld; /* Dynamic section of the shared object. */
|
||||
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
|
||||
|
||||
/* All following members are internal to the dynamic linker.
|
||||
They may change without notice. */
|
||||
|
||||
const char *l_libname; /* Name requested (before search). */
|
||||
/* Indexed pointers to dynamic section.
|
||||
[0,DT_NUM) are indexed by the processor-independent tags.
|
||||
[DT_NUM,DT_NUM+DT_PROCNUM] are indexed by the tag minus DT_LOPROC. */
|
||||
Elf32_Dyn *l_info[DT_NUM + DT_PROCNUM];
|
||||
const Elf32_Phdr *l_phdr; /* Pointer to program header table in core. */
|
||||
Elf32_Word l_phnum; /* Number of program header entries. */
|
||||
Elf32_Addr l_entry; /* Entry point location. */
|
||||
|
||||
/* Symbol hash table. */
|
||||
Elf32_Word l_nbuckets;
|
||||
const Elf32_Word *l_buckets, *l_chain;
|
||||
|
||||
unsigned int l_opencount; /* Reference count for dlopen/dlclose. */
|
||||
enum /* Where this object came from. */
|
||||
{
|
||||
lt_executable, /* The main executable program. */
|
||||
lt_interpreter, /* The interpreter: the dynamic linker. */
|
||||
lt_library, /* Library needed by main executable. */
|
||||
lt_loaded, /* Extra run-time loaded shared object. */
|
||||
} l_type:2;
|
||||
unsigned int l_deps_loaded:1; /* Nonzero if DT_NEEDED items loaded. */
|
||||
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
|
||||
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
|
||||
unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */
|
||||
};
|
||||
|
||||
/* Internal functions of the run-time dynamic linker.
|
||||
These can be accessed if you link again the dynamic linker
|
||||
as a shared library, as in `-lld' or `/lib/ld.so' explicitly;
|
||||
but are not normally of interest to user programs.
|
||||
|
||||
The `-ldl' library functions in <dlfcn.h> provide a simple
|
||||
user interface to run-time dynamic linking. */
|
||||
|
||||
|
||||
/* File descriptor referring to the zero-fill device. */
|
||||
extern int _dl_zerofd;
|
||||
|
||||
/* OS-dependent function to open the zero-fill device. */
|
||||
extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */
|
||||
|
||||
/* OS-dependent function to write a message on the standard output.
|
||||
All arguments are `const char *'; args until a null pointer
|
||||
are concatenated to form the message to print. */
|
||||
extern void _dl_sysdep_message (const char *string, ...);
|
||||
|
||||
/* OS-dependent function to give a fatal error message and exit
|
||||
when the dynamic linker fails before the program is fully linked.
|
||||
All arguments are `const char *'; args until a null pointer
|
||||
are concatenated to form the message to print. */
|
||||
extern void _dl_sysdep_fatal (const char *string, ...)
|
||||
__attribute__ ((__noreturn__));
|
||||
|
||||
/* Nonzero if the program should be "secure" (i.e. it's setuid or somesuch).
|
||||
This tells the dynamic linker to ignore environment variables. */
|
||||
extern int _dl_secure;
|
||||
|
||||
/* This function is called by all the internal dynamic linker functions
|
||||
when they encounter an error. ERRCODE is either an `errno' code or
|
||||
zero; OBJECT is the name of the problematical shared object, or null if
|
||||
it is a general problem; ERRSTRING is a string describing the specific
|
||||
problem. */
|
||||
|
||||
extern void _dl_signal_error (int errcode,
|
||||
const char *object,
|
||||
const char *errstring)
|
||||
__attribute__ ((__noreturn__));
|
||||
|
||||
/* Call OPERATE, catching errors from `dl_signal_error'. If there is no
|
||||
error, *ERRSTRING is set to null. If there is an error, *ERRSTRING and
|
||||
*OBJECT are set to the strings passed to _dl_signal_error, and the error
|
||||
code passed is the return value. */
|
||||
extern int _dl_catch_error (const char **errstring,
|
||||
const char **object,
|
||||
void (*operate) (void));
|
||||
|
||||
|
||||
/* Helper function for <dlfcn.h> functions. Runs the OPERATE function via
|
||||
_dl_catch_error. Returns zero for success, nonzero for failure; and
|
||||
arranges for `dlerror' to return the error details. */
|
||||
extern int _dlerror_run (void (*operate) (void));
|
||||
|
||||
|
||||
/* Open the shared object NAME and map in its segments.
|
||||
LOADER's DT_RPATH is used in searching for NAME.
|
||||
If the object is already opened, returns its existing map. */
|
||||
extern struct link_map *_dl_map_object (struct link_map *loader,
|
||||
const char *name);
|
||||
|
||||
/* Similar, but file found at REALNAME and opened on FD.
|
||||
REALNAME must malloc'd storage and is used in internal data structures. */
|
||||
extern struct link_map *_dl_map_object_from_fd (const char *name,
|
||||
int fd, char *realname);
|
||||
|
||||
/* Cache the locations of MAP's hash table. */
|
||||
extern void _dl_setup_hash (struct link_map *map);
|
||||
|
||||
|
||||
/* Search loaded objects' symbol tables for a definition of the symbol
|
||||
referred to by UNDEF. *SYM is the symbol table entry containing the
|
||||
reference; it is replaced with the defining symbol, and the base load
|
||||
address of the defining object is returned. SYMBOL_SCOPE is the head of
|
||||
the chain used for searching. REFERENCE_NAME should name the object
|
||||
containing the reference; it is used in error messages. If NOSELF is
|
||||
nonzero, them *SYM itself cannot define the value; another binding must
|
||||
be found. */
|
||||
extern Elf32_Addr _dl_lookup_symbol (const char *undef,
|
||||
const Elf32_Sym **sym,
|
||||
struct link_map *symbol_scope,
|
||||
const char *reference_name,
|
||||
int noself);
|
||||
|
||||
|
||||
/* List of objects currently loaded. */
|
||||
extern struct link_map *_dl_loaded;
|
||||
|
||||
/* Tail of that list which were loaded at startup. */
|
||||
extern struct link_map *_dl_startup_loaded;
|
||||
|
||||
/* Allocate a `struct link_map' for a new object being loaded,
|
||||
and enter it into the _dl_loaded list. */
|
||||
extern struct link_map *_dl_new_object (char *realname, const char *libname,
|
||||
int type);
|
||||
|
||||
/* Relocate the given object (if it hasn't already been).
|
||||
If LAZY is nonzero, don't relocate its PLT. */
|
||||
extern void _dl_relocate_object (struct link_map *map, int lazy);
|
||||
|
||||
/* Return the address of the next initializer function not yet run.
|
||||
When there are no more initializers to be run, this returns zero.
|
||||
The functions are returned in the order they should be called. */
|
||||
extern Elf32_Addr _dl_init_next (void);
|
||||
|
||||
/* Call the finalizer functions of all shared objects whose
|
||||
initializer functions have completed. */
|
||||
extern void _dl_fini (void);
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
||||
says what change is taking place. This function's address is
|
||||
the value of the `r_brk' member. */
|
||||
extern void _dl_r_debug_state (void);
|
||||
|
||||
|
||||
#endif /* link.h */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user